All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 00/17] ASoC: Intel: AVS - Audio DSP for cAVS
@ 2022-03-04 14:57 Cezary Rojewski
  2022-03-04 14:57 ` [PATCH v3 01/17] ALSA: hda: Add helper macros for DSP capable devices Cezary Rojewski
                   ` (16 more replies)
  0 siblings, 17 replies; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-04 14:57 UTC (permalink / raw)
  To: alsa-devel
  Cc: Cezary Rojewski, rad, upstream, harshapriya.n, tiwai,
	pierre-louis.bossart, hdegoede, broonie, amadeuszx.slawinski,
	cujomalainey, lma

A continuation of cleanup work of Intel SST solutions found in
sound/soc/intel/. With two major chapters released last year catpt [1]
and removal of haswell solution [2], time has come for Skylake-driver.

Througout 2019, 2020 and 2021 Skylake-driver has had many fixes applied
and even attempts of refactors as seen in fundamental overhaul [3], IPC
flow adjustments [4] and LARGE_CONFIG overhaul [5] series.
Unfortunately, story repeats itself - problems are found within the core
of a driver. Painting it with different colors does not change the fact
that is it still a house of cards. As changes needed to address those
issues would make Skylake solution incompatible with its previous
revisions, a decision has been made to provide a new solution instead.
In time it would deprecate and replace Skylake-driver.

That solution has been called AVS - from AudioDSP architecture name:
Audio-Voice-Speech. It is meant to provide support for the exact same
range of platforms as its predecessor: SKL, KBL, AML and APL.

Note: this series is dependent upon HDA-series [6] which exposes several
codec-organization functions allowing for reduced code size on
avs-driver side.

Note: this series does not add fully functional driver as its size would
get out of control. Here, focus is put on adding IPC protocol and code
loading code.


Changes v2 -> v3:
- fixed variable initialization errors mentioned by sparse


Changes v1 -> v2:
Almost all updates here are thanks to feedback from Pierre.

- several comments and few kernel-docs have been added in areas which
  felt more or less unclear
- avs_ipc_wait_busy_completion() now spins up to 'repeats_left' number
  of times before giving up
- 'adsp_ba' field of struct avs_dev has been renamed to 'dsp_ba'
- 'dops' field of struct avs_spec has been renamed to 'dsp_ops'
- IPC abstraction has been simplified: SKL_ADSP_REG_HIP* regs are used
  directly
- fixed allnoconfig with AVS enabled compilation issues
- fixed code loading error paths: previously requested firmware is now
  released before function return to the caller
- code and function arguments tied to D0IX support have been removed
  from this patchset and will be part of followup series adding that
  feature instead
- enriched dev_err() messages in avs_dsp_get_core() and
  avs_dsp_put_core()
- numerous wording fixes used in power/reset/stall DSP operations


Changes RFC v1 [7]: -> v1:
- separated HDA codec-organization patches, path and topology handling,
  PCM and complementary features such as recovery from this series to
  ease the review process
- fixed EXPORT_SYMBOL_GPL for exported members of ASoC framework
- result of stall() is now checked when sending ROM message
- result of snd_hdac_ext_stream_set_spib() is now checked when loading
  basefw
- if basefw is not ready, notification processing is now skipped
- documented several topology parsing helpers


Changes [internal] RFC v2 -> [public] RFC v1:
- dropped any sysfs related changes from this series, moved to follow up
  one
- dropped entire subscription-mechanism found in ipc.c. Handlers that
  are delegated to service certain firmware notifications are now called
  directly
- fixed kernel doc for snd_soc_dapm_new_dai_widgets() as reported by ikp
- prefixed snd_hda_codec_device_init() as suggested by Amadeo
- improved comments for d0ix transitions for APL-based platforms as
  suggested by Pierre
- a ton of spelling related fixes in most of the commit messages
- fixed remaining warnings pointed by scan-build (variable assigned but
  not used)
- replaced most of 'cAVS X.Y' expression usages with 'platform-based'
  equivalents as suggested by Pierre e.g.: cAVS 1.5 -> SKL-based


Changes [internal] RFC v1 -> [internal] RFC v2:
- fixed memleak caused by lack of kfree(vols) if memory allocation fails
  in avs_peakvol_create() as reported by Curtis
- fixed missing 'i' iterator incrementation in avs_widget_ready()
  causing reference loss as reported by Curtis
- replace hardcode: 0x40 usage with snd_hdac_calc_stream_format as
  suggested by Curtis.
  In consequence, readability for all code loading (CL) procedues has
  increased and such approach auto-documents the CL stream preparation

- updated behavior of all index-fetching functions found in utils.c:
  avs_module_entry_index(), avs_module_id_entry_index() and follow ups:
  avs_get_module_entry(), avs_get_module_id_entry() to better conform to
  linux-kernel standard when no entry is found (return -ENOENT) rather
  than C++ standard (return -1, what in kernel case translated to -EPERM)
  as suggested by Curtis and Peter
- several suggestions have been made regarding spacing, and so far, I've
  agreed and applied with all of them. None proposed seemed out of place
  or redundant

- avs_path_stop() renamed to avs_path_pause() pipeline states are
  represented by RESET/PAUSED/RUNNING. avs_path_reset() and
  avs_path_run() were already there and avs_path_stop() just didn't look
  cohesive
- added missing parsers for num_output_pin and num_input_pin which are
  required for custom modules such as WAVES or DSM
- dropped 'priv_param_length' from custom module descriptor as this
  field is obsolete in firmware

- parse_dictionary() has been split into parse_dictionary_header() and
  parse_dictionary_entries() to drop code duplication present in several
  parsing function which could not re-use entire parse_dictionary()
- added avs_tplg_vendor_array_lookup_next() and
  avs_tplg_vendor_entry_next() to drop code duplicated present in several
  parsing functions. This change greatly impacted readability of all
  parsers
- parsing helpers such avs_tplg_vendor_array_lookup() now return offset
  by updating specified in function argument list u32 *offset variable.
  This is to address problem when u32 offset would be greater than max
  int, which is the return type for these functions
- AVS_DEFINE_PTR_PARSER() macro has been introduced to drop code
  duplication for all ptr-parsing users

- all struct avs_path_module creators have had their declaration
  updated: function argument *owner ceased to exist as it could already
  be accessed by mod->owner

- fixed the order of operation for conditional paths (e.g.: echo
  reference) so these are no longer controlled by "source" path and
  instead are impacted by state changes of source and sink paths both.
  Previously only source path e.g. playback sourcing echo reference
  would trigger RUNNING status for conditional path. Equivalent RUNNING
  on WoV path which is in this case sink path, would not do so, leading
  to order-of-operation problems. Behavior has been changed to: both
  source and sink need to be RUNNING for conditional path to be set to
  RUNNING too. PAUSED for either source or sink will cause PAUSED
  transition for conditional path.
- to achieve the above, path states are now saved in 'state' i.e. new
  u32 field for struct avs_path

- resigned from fw_filename field usage in favour of newly added
  tplg_filename for machine board descriptors as suggested by Pierre
- platform descriptor fields have had their names update better reflect
  their purpose as suggested by Pierre
- fixed comp_list missing locking when manipulated
- all message senders now accept request as pointer as suggeseted by
  Peter
- resigned of AZX_ usage for all ADSP-related registers, leaving them
  only for HOST memory space related operations
- fixed disable path for core DSP operations: power/reset/stall as
  reported by Peter

- safety when locking between received responses (reply vs notification)
  has been lowered as suggested by Pierre. Most usages are not performed
  in IRQ context and none is done in hard-IRQ one
- s/master/main/ plus AVS_MAIN_CORE_MASK has replaced ->master_mask
- several functions have had their logging updated - logs have been
  moved to lower level functions as suggested by Pierre
- hdac_ext_stream usage has been streamlined to estream, hdac_streams
  are represented by hstream instead
- hw_params() are resilient to scenarios when they are called mutliple
  times as reported by Pierre
- avs_dsp_enable() now collapses if any of its steps fails as reported
  by Pierre and Peter
- avs_module_ida_empty() now returns value of type bool as suggested by
  Bard


[1]: https://www.spinics.net/lists/alsa-devel/msg116440.html
[2]: https://www.spinics.net/lists/alsa-devel/msg116901.html
[3]: https://www.spinics.net/lists/alsa-devel/msg94199.html
[4]: https://www.spinics.net/lists/alsa-devel/msg92588.html
[5]: https://lore.kernel.org/all/20190808181549.12521-1-cezary.rojewski@intel.com/
[6]: https://lore.kernel.org/alsa-devel/20220207114906.3759800-1-cezary.rojewski@intel.com/T/#t
[7]: https://lore.kernel.org/all/20211208111301.1817725-1-cezary.rojewski@intel.com/


Cezary Rojewski (17):
  ALSA: hda: Add helper macros for DSP capable devices
  ASoC: Export DAI register and widget ctor and dctor functions
  ASoC: Intel: Introduce AVS driver
  ASoC: Intel: avs: Inter process communication
  ASoC: Intel: avs: Add code loading requests
  ASoC: Intel: avs: Add pipeline management requests
  ASoC: Intel: avs: Add module management requests
  ASoC: Intel: avs: Add power management requests
  ASoC: Intel: avs: Add ROM requests
  ASoC: Intel: avs: Add basefw runtime-parameter requests
  ASoC: Intel: avs: Firmware resources management utilities
  ASoC: Intel: avs: Declare module configuration types
  ASoC: Intel: avs: Dynamic firmware resources management
  ASoC: Intel: avs: General code loading flow
  ASoC: Intel: avs: Implement CLDMA transfer
  ASoC: Intel: avs: Code loading over CLDMA
  ASoC: Intel: avs: Code loading over HDA

 include/sound/hdaudio.h         |   2 +
 include/sound/hdaudio_ext.h     |  50 +++
 include/sound/soc-dapm.h        |   1 +
 sound/soc/intel/Kconfig         |  12 +
 sound/soc/intel/Makefile        |   1 +
 sound/soc/intel/avs/Makefile    |   6 +
 sound/soc/intel/avs/avs.h       | 248 +++++++++++
 sound/soc/intel/avs/cldma.c     | 317 ++++++++++++++
 sound/soc/intel/avs/cldma.h     |  29 ++
 sound/soc/intel/avs/core.c      |  62 +++
 sound/soc/intel/avs/dsp.c       | 303 +++++++++++++
 sound/soc/intel/avs/ipc.c       | 393 +++++++++++++++++
 sound/soc/intel/avs/loader.c    | 607 +++++++++++++++++++++++++
 sound/soc/intel/avs/messages.c  | 697 +++++++++++++++++++++++++++++
 sound/soc/intel/avs/messages.h  | 753 ++++++++++++++++++++++++++++++++
 sound/soc/intel/avs/registers.h |  75 ++++
 sound/soc/intel/avs/utils.c     | 301 +++++++++++++
 sound/soc/soc-core.c            |   1 +
 sound/soc/soc-dapm.c            |  15 +
 19 files changed, 3873 insertions(+)
 create mode 100644 sound/soc/intel/avs/Makefile
 create mode 100644 sound/soc/intel/avs/avs.h
 create mode 100644 sound/soc/intel/avs/cldma.c
 create mode 100644 sound/soc/intel/avs/cldma.h
 create mode 100644 sound/soc/intel/avs/core.c
 create mode 100644 sound/soc/intel/avs/dsp.c
 create mode 100644 sound/soc/intel/avs/ipc.c
 create mode 100644 sound/soc/intel/avs/loader.c
 create mode 100644 sound/soc/intel/avs/messages.c
 create mode 100644 sound/soc/intel/avs/messages.h
 create mode 100644 sound/soc/intel/avs/registers.h
 create mode 100644 sound/soc/intel/avs/utils.c

-- 
2.25.1


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

* [PATCH v3 01/17] ALSA: hda: Add helper macros for DSP capable devices
  2022-03-04 14:57 [PATCH v3 00/17] ASoC: Intel: AVS - Audio DSP for cAVS Cezary Rojewski
@ 2022-03-04 14:57 ` Cezary Rojewski
  2022-03-04 14:57 ` [PATCH v3 02/17] ASoC: Export DAI register and widget ctor and dctor functions Cezary Rojewski
                   ` (15 subsequent siblings)
  16 siblings, 0 replies; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-04 14:57 UTC (permalink / raw)
  To: alsa-devel
  Cc: Cezary Rojewski, rad, upstream, harshapriya.n, tiwai,
	pierre-louis.bossart, hdegoede, broonie, amadeuszx.slawinski,
	cujomalainey, lma

HDAudio drivers make heavy use of I/O operations. Declare a range of
update, read and write helpers similar to those available for HDAudio
legacy driver. These macros are used by AVS driver to improve code
readability.

Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 include/sound/hdaudio.h     |  2 ++
 include/sound/hdaudio_ext.h | 50 +++++++++++++++++++++++++++++++++++++
 2 files changed, 52 insertions(+)

diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h
index 6a90ce405e60..69907260b9ce 100644
--- a/include/sound/hdaudio.h
+++ b/include/sound/hdaudio.h
@@ -448,6 +448,8 @@ static inline u16 snd_hdac_reg_readw(struct hdac_bus *bus, void __iomem *addr)
 
 #define snd_hdac_reg_writel(bus, addr, val)	writel(val, addr)
 #define snd_hdac_reg_readl(bus, addr)	readl(addr)
+#define snd_hdac_reg_writeq(bus, addr, val)	writeq(val, addr)
+#define snd_hdac_reg_readq(bus, addr)		readq(addr)
 
 /*
  * macros for easy use
diff --git a/include/sound/hdaudio_ext.h b/include/sound/hdaudio_ext.h
index b0c8e4936168..d26234f9ee46 100644
--- a/include/sound/hdaudio_ext.h
+++ b/include/sound/hdaudio_ext.h
@@ -2,6 +2,8 @@
 #ifndef __SOUND_HDAUDIO_EXT_H
 #define __SOUND_HDAUDIO_EXT_H
 
+#include <linux/io-64-nonatomic-lo-hi.h>
+#include <linux/iopoll.h>
 #include <sound/hdaudio.h>
 
 int snd_hdac_ext_bus_init(struct hdac_bus *bus, struct device *dev,
@@ -144,6 +146,54 @@ void snd_hdac_ext_bus_link_power(struct hdac_device *codec, bool enable);
 	writew(((readw(addr + reg) & ~(mask)) | (val)), \
 		addr + reg)
 
+#define snd_hdac_adsp_writeb(chip, reg, value) \
+	snd_hdac_reg_writeb(chip, (chip)->dsp_ba + (reg), value)
+#define snd_hdac_adsp_readb(chip, reg) \
+	snd_hdac_reg_readb(chip, (chip)->dsp_ba + (reg))
+#define snd_hdac_adsp_writew(chip, reg, value) \
+	snd_hdac_reg_writew(chip, (chip)->dsp_ba + (reg), value)
+#define snd_hdac_adsp_readw(chip, reg) \
+	snd_hdac_reg_readw(chip, (chip)->dsp_ba + (reg))
+#define snd_hdac_adsp_writel(chip, reg, value) \
+	snd_hdac_reg_writel(chip, (chip)->dsp_ba + (reg), value)
+#define snd_hdac_adsp_readl(chip, reg) \
+	snd_hdac_reg_readl(chip, (chip)->dsp_ba + (reg))
+#define snd_hdac_adsp_writeq(chip, reg, value) \
+	snd_hdac_reg_writeq(chip, (chip)->dsp_ba + (reg), value)
+#define snd_hdac_adsp_readq(chip, reg) \
+	snd_hdac_reg_readq(chip, (chip)->dsp_ba + (reg))
+
+#define snd_hdac_adsp_updateb(chip, reg, mask, val) \
+	snd_hdac_adsp_writeb(chip, reg, \
+			(snd_hdac_adsp_readb(chip, reg) & ~(mask)) | (val))
+#define snd_hdac_adsp_updatew(chip, reg, mask, val) \
+	snd_hdac_adsp_writew(chip, reg, \
+			(snd_hdac_adsp_readw(chip, reg) & ~(mask)) | (val))
+#define snd_hdac_adsp_updatel(chip, reg, mask, val) \
+	snd_hdac_adsp_writel(chip, reg, \
+			(snd_hdac_adsp_readl(chip, reg) & ~(mask)) | (val))
+#define snd_hdac_adsp_updateq(chip, reg, mask, val) \
+	snd_hdac_adsp_writeq(chip, reg, \
+			(snd_hdac_adsp_readq(chip, reg) & ~(mask)) | (val))
+
+#define snd_hdac_adsp_readb_poll(chip, reg, val, cond, delay_us, timeout_us) \
+	readb_poll_timeout((chip)->dsp_ba + (reg), val, cond, \
+			   delay_us, timeout_us)
+#define snd_hdac_adsp_readw_poll(chip, reg, val, cond, delay_us, timeout_us) \
+	readw_poll_timeout((chip)->dsp_ba + (reg), val, cond, \
+			   delay_us, timeout_us)
+#define snd_hdac_adsp_readl_poll(chip, reg, val, cond, delay_us, timeout_us) \
+	readl_poll_timeout((chip)->dsp_ba + (reg), val, cond, \
+			   delay_us, timeout_us)
+#define snd_hdac_adsp_readq_poll(chip, reg, val, cond, delay_us, timeout_us) \
+	readq_poll_timeout((chip)->dsp_ba + (reg), val, cond, \
+			   delay_us, timeout_us)
+#define snd_hdac_stream_readb_poll(strm, reg, val, cond, delay_us, timeout_us) \
+	readb_poll_timeout((strm)->sd_addr + AZX_REG_ ## reg, val, cond, \
+			   delay_us, timeout_us)
+#define snd_hdac_stream_readl_poll(strm, reg, val, cond, delay_us, timeout_us) \
+	readl_poll_timeout((strm)->sd_addr + AZX_REG_ ## reg, val, cond, \
+			   delay_us, timeout_us)
 
 struct hdac_ext_device;
 
-- 
2.25.1


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

* [PATCH v3 02/17] ASoC: Export DAI register and widget ctor and dctor functions
  2022-03-04 14:57 [PATCH v3 00/17] ASoC: Intel: AVS - Audio DSP for cAVS Cezary Rojewski
  2022-03-04 14:57 ` [PATCH v3 01/17] ALSA: hda: Add helper macros for DSP capable devices Cezary Rojewski
@ 2022-03-04 14:57 ` Cezary Rojewski
  2022-03-04 14:57 ` [PATCH v3 03/17] ASoC: Intel: Introduce AVS driver Cezary Rojewski
                   ` (14 subsequent siblings)
  16 siblings, 0 replies; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-04 14:57 UTC (permalink / raw)
  To: alsa-devel
  Cc: Cezary Rojewski, rad, upstream, harshapriya.n, tiwai,
	pierre-louis.bossart, hdegoede, broonie, amadeuszx.slawinski,
	cujomalainey, lma

To allow for more flexibility i.e. populating component DAIs dynamically
during its initialization, without being limited to topology loading
procedure, expose snd_soc_register(), snd_soc_dapm_new_dai_widgets() and
snd_soc_dapm_free_widget() functions.

Allows users to first check available resources e.g. number of PCMs
supported by HDAudio codec before allocating the number of DAPM
widgets needed. This prevents superfluous objects from being created or
allows driver to adjust to situation when resources are limited.

Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 include/sound/soc-dapm.h |  1 +
 sound/soc/soc-core.c     |  1 +
 sound/soc/soc-dapm.c     | 15 +++++++++++++++
 3 files changed, 17 insertions(+)

diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index c3039e97929a..ebb8e7a7fc29 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -429,6 +429,7 @@ struct snd_soc_dapm_widget *snd_soc_dapm_new_control_unlocked(
 		const struct snd_soc_dapm_widget *widget);
 int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
 				 struct snd_soc_dai *dai);
+void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w);
 int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card);
 void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card);
 
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 259429526c84..1f0564ed3a75 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -2465,6 +2465,7 @@ struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component,
 	dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name);
 	return dai;
 }
+EXPORT_SYMBOL_GPL(snd_soc_register_dai);
 
 /**
  * snd_soc_unregister_dais - Unregister DAIs from the ASoC core
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index b06c5682445c..b435b5c4cfb7 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -2484,6 +2484,12 @@ static void dapm_free_path(struct snd_soc_dapm_path *path)
 	kfree(path);
 }
 
+/**
+ * snd_soc_dapm_free_widget - Free specified widget
+ * @w: widget to free
+ *
+ * Removes widget from all paths and frees memory occupied by it.
+ */
 void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w)
 {
 	struct snd_soc_dapm_path *p, *next_p;
@@ -2506,6 +2512,7 @@ void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w)
 	kfree_const(w->sname);
 	kfree(w);
 }
+EXPORT_SYMBOL_GPL(snd_soc_dapm_free_widget);
 
 void snd_soc_dapm_reset_cache(struct snd_soc_dapm_context *dapm)
 {
@@ -4208,6 +4215,13 @@ snd_soc_dapm_new_dai(struct snd_soc_card *card,
 	return ERR_PTR(ret);
 }
 
+/**
+ * snd_soc_dapm_new_dai_widgets - Create new DAPM widgets
+ * @dapm: DAPM context
+ * @dai: parent DAI
+ *
+ * Returns 0 on success, error code otherwise.
+ */
 int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
 				 struct snd_soc_dai *dai)
 {
@@ -4253,6 +4267,7 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(snd_soc_dapm_new_dai_widgets);
 
 int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
 {
-- 
2.25.1


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

* [PATCH v3 03/17] ASoC: Intel: Introduce AVS driver
  2022-03-04 14:57 [PATCH v3 00/17] ASoC: Intel: AVS - Audio DSP for cAVS Cezary Rojewski
  2022-03-04 14:57 ` [PATCH v3 01/17] ALSA: hda: Add helper macros for DSP capable devices Cezary Rojewski
  2022-03-04 14:57 ` [PATCH v3 02/17] ASoC: Export DAI register and widget ctor and dctor functions Cezary Rojewski
@ 2022-03-04 14:57 ` Cezary Rojewski
  2022-03-04 15:51   ` Ranjani Sridharan
  2022-03-04 14:57 ` [PATCH v3 04/17] ASoC: Intel: avs: Inter process communication Cezary Rojewski
                   ` (13 subsequent siblings)
  16 siblings, 1 reply; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-04 14:57 UTC (permalink / raw)
  To: alsa-devel
  Cc: Cezary Rojewski, rad, upstream, harshapriya.n, tiwai,
	pierre-louis.bossart, hdegoede, broonie, amadeuszx.slawinski,
	cujomalainey, lma

Declare base structures and core DSP operations for the avs solution.
The base structures describe PCI HDAudio bus device and platform-type
differentiations. First set of operations added controls the lifecycle
of any Audio DSP core: (un)powering, (un)resetting and (un)stalling.

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         |  11 ++++
 sound/soc/intel/Makefile        |   1 +
 sound/soc/intel/avs/Makefile    |   5 ++
 sound/soc/intel/avs/avs.h       |  71 +++++++++++++++++++++
 sound/soc/intel/avs/dsp.c       | 107 ++++++++++++++++++++++++++++++++
 sound/soc/intel/avs/registers.h |  22 +++++++
 6 files changed, 217 insertions(+)
 create mode 100644 sound/soc/intel/avs/Makefile
 create mode 100644 sound/soc/intel/avs/avs.h
 create mode 100644 sound/soc/intel/avs/dsp.c
 create mode 100644 sound/soc/intel/avs/registers.h

diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index f3a4a907b29d..e9768c4aa1a9 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -209,5 +209,16 @@ config SND_SOC_INTEL_KEEMBAY
 	  If you have a Intel Keembay platform then enable this option
 	  by saying Y or m.
 
+config SND_SOC_INTEL_AVS
+	tristate "Intel AVS driver"
+	depends on PCI && ACPI
+	depends on COMMON_CLK
+	select SND_SOC_ACPI
+	select SND_HDA_EXT_CORE
+	help
+	  Enable support for Intel(R) cAVS 1.5 platforms with DSP
+	  capabilities. This includes Skylake, Kabylake, Amberlake and
+	  Apollolake.
+
 # ASoC codec drivers
 source "sound/soc/intel/boards/Kconfig"
diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile
index 7c5038803be7..d44b2652c707 100644
--- a/sound/soc/intel/Makefile
+++ b/sound/soc/intel/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM) += atom/
 obj-$(CONFIG_SND_SOC_INTEL_CATPT) += catpt/
 obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE_COMMON) += skylake/
 obj-$(CONFIG_SND_SOC_INTEL_KEEMBAY) += keembay/
+obj-$(CONFIG_SND_SOC_INTEL_AVS) += avs/
 
 # Machine support
 obj-$(CONFIG_SND_SOC) += boards/
diff --git a/sound/soc/intel/avs/Makefile b/sound/soc/intel/avs/Makefile
new file mode 100644
index 000000000000..5f7976a95fe2
--- /dev/null
+++ b/sound/soc/intel/avs/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+snd-soc-avs-objs := dsp.o
+
+obj-$(CONFIG_SND_SOC_INTEL_AVS) += snd-soc-avs.o
diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h
new file mode 100644
index 000000000000..d4e6310e4bf7
--- /dev/null
+++ b/sound/soc/intel/avs/avs.h
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright(c) 2021 Intel Corporation. All rights reserved.
+ *
+ * Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+ *          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+ */
+
+#ifndef __SOUND_SOC_INTEL_AVS_H
+#define __SOUND_SOC_INTEL_AVS_H
+
+#include <linux/device.h>
+#include <sound/hda_codec.h>
+
+struct avs_dev;
+
+struct avs_dsp_ops {
+	int (* const power)(struct avs_dev *, u32, bool);
+	int (* const reset)(struct avs_dev *, u32, bool);
+	int (* const stall)(struct avs_dev *, u32, bool);
+};
+
+#define avs_dsp_op(adev, op, ...) \
+	((adev)->spec->dsp_ops->op(adev, ## __VA_ARGS__))
+
+#define avs_platattr_test(adev, attr) \
+	((adev)->spec->attributes & AVS_PLATATTR_##attr)
+
+/* Platform specific descriptor */
+struct avs_spec {
+	const char *name;
+
+	const struct avs_dsp_ops *const dsp_ops;
+
+	const u32 core_init_mask;	/* used during DSP boot */
+	const u64 attributes;		/* bitmask of AVS_PLATATTR_* */
+};
+
+/*
+ * struct avs_dev - Intel HD-Audio driver data
+ *
+ * @dev: PCI device
+ * @dsp_ba: DSP bar address
+ * @spec: platform-specific descriptor
+ */
+struct avs_dev {
+	struct hda_bus base;
+	struct device *dev;
+
+	void __iomem *dsp_ba;
+	const struct avs_spec *spec;
+};
+
+/* from hda_bus to avs_dev */
+#define hda_to_avs(hda) container_of(hda, struct avs_dev, base)
+/* from hdac_bus to avs_dev */
+#define hdac_to_avs(hdac) hda_to_avs(to_hda_bus(hdac))
+/* from device to avs_dev */
+#define to_avs_dev(dev) \
+({ \
+	struct hdac_bus *__bus = dev_get_drvdata(dev); \
+	hdac_to_avs(__bus); \
+})
+
+int avs_dsp_core_power(struct avs_dev *adev, u32 core_mask, bool power);
+int avs_dsp_core_reset(struct avs_dev *adev, u32 core_mask, bool reset);
+int avs_dsp_core_stall(struct avs_dev *adev, u32 core_mask, bool stall);
+int avs_dsp_core_enable(struct avs_dev *adev, u32 core_mask);
+int avs_dsp_core_disable(struct avs_dev *adev, u32 core_mask);
+
+#endif /* __SOUND_SOC_INTEL_AVS_H */
diff --git a/sound/soc/intel/avs/dsp.c b/sound/soc/intel/avs/dsp.c
new file mode 100644
index 000000000000..eb9d941fe6cf
--- /dev/null
+++ b/sound/soc/intel/avs/dsp.c
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/module.h>
+#include <sound/hdaudio_ext.h>
+#include "avs.h"
+#include "registers.h"
+
+#define AVS_ADSPCS_INTERVAL_US		500
+#define AVS_ADSPCS_TIMEOUT_US		50000
+
+int avs_dsp_core_power(struct avs_dev *adev, u32 core_mask, bool power)
+{
+	u32 value, mask, reg;
+	int ret;
+
+	mask = AVS_ADSPCS_SPA_MASK(core_mask);
+	value = power ? mask : 0;
+
+	snd_hdac_adsp_updatel(adev, AVS_ADSP_REG_ADSPCS, mask, value);
+
+	mask = AVS_ADSPCS_CPA_MASK(core_mask);
+	value = power ? mask : 0;
+
+	ret = snd_hdac_adsp_readl_poll(adev, AVS_ADSP_REG_ADSPCS,
+				       reg, (reg & mask) == value,
+				       AVS_ADSPCS_INTERVAL_US,
+				       AVS_ADSPCS_TIMEOUT_US);
+	if (ret)
+		dev_err(adev->dev, "core_mask %d power %s failed: %d\n",
+			core_mask, power ? "on" : "off", ret);
+
+	return ret;
+}
+
+int avs_dsp_core_reset(struct avs_dev *adev, u32 core_mask, bool reset)
+{
+	u32 value, mask, reg;
+	int ret;
+
+	mask = AVS_ADSPCS_CRST_MASK(core_mask);
+	value = reset ? mask : 0;
+
+	snd_hdac_adsp_updatel(adev, AVS_ADSP_REG_ADSPCS, mask, value);
+
+	ret = snd_hdac_adsp_readl_poll(adev, AVS_ADSP_REG_ADSPCS,
+				       reg, (reg & mask) == value,
+				       AVS_ADSPCS_INTERVAL_US,
+				       AVS_ADSPCS_TIMEOUT_US);
+	if (ret)
+		dev_err(adev->dev, "core_mask %d %s reset failed: %d\n",
+			core_mask, reset ? "enter" : "exit", ret);
+
+	return ret;
+}
+
+int avs_dsp_core_stall(struct avs_dev *adev, u32 core_mask, bool stall)
+{
+	u32 value, mask, reg;
+	int ret;
+
+	mask = AVS_ADSPCS_CSTALL_MASK(core_mask);
+	value = stall ? mask : 0;
+
+	snd_hdac_adsp_updatel(adev, AVS_ADSP_REG_ADSPCS, mask, value);
+
+	ret = snd_hdac_adsp_readl_poll(adev, AVS_ADSP_REG_ADSPCS,
+				       reg, (reg & mask) == value,
+				       AVS_ADSPCS_INTERVAL_US,
+				       AVS_ADSPCS_TIMEOUT_US);
+	if (ret)
+		dev_err(adev->dev, "core_mask %d %sstall failed: %d\n",
+			core_mask, stall ? "" : "un", ret);
+
+	return ret;
+}
+
+int avs_dsp_core_enable(struct avs_dev *adev, u32 core_mask)
+{
+	int ret;
+
+	ret = avs_dsp_op(adev, power, core_mask, true);
+	if (ret)
+		return ret;
+
+	ret = avs_dsp_op(adev, reset, core_mask, false);
+	if (ret)
+		return ret;
+
+	return avs_dsp_op(adev, stall, core_mask, false);
+}
+
+int avs_dsp_core_disable(struct avs_dev *adev, u32 core_mask)
+{
+	/* No error checks to allow for complete DSP shutdown. */
+	avs_dsp_op(adev, stall, core_mask, true);
+	avs_dsp_op(adev, reset, core_mask, true);
+
+	return avs_dsp_op(adev, power, core_mask, false);
+}
+
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/intel/avs/registers.h b/sound/soc/intel/avs/registers.h
new file mode 100644
index 000000000000..e0b6c8ffe633
--- /dev/null
+++ b/sound/soc/intel/avs/registers.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright(c) 2021 Intel Corporation. All rights reserved.
+ *
+ * Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+ *          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+ */
+
+#ifndef __SOUND_SOC_INTEL_AVS_REGS_H
+#define __SOUND_SOC_INTEL_AVS_REGS_H
+
+/* Intel HD Audio General DSP Registers */
+#define AVS_ADSP_GEN_BASE		0x0
+#define AVS_ADSP_REG_ADSPCS		(AVS_ADSP_GEN_BASE + 0x04)
+
+#define AVS_ADSPCS_CRST_MASK(cm)	(cm)
+#define AVS_ADSPCS_CSTALL_MASK(cm)	((cm) << 8)
+#define AVS_ADSPCS_SPA_MASK(cm)		((cm) << 16)
+#define AVS_ADSPCS_CPA_MASK(cm)		((cm) << 24)
+#define AVS_MAIN_CORE_MASK		BIT(0)
+
+#endif /* __SOUND_SOC_INTEL_AVS_REGS_H */
-- 
2.25.1


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

* [PATCH v3 04/17] ASoC: Intel: avs: Inter process communication
  2022-03-04 14:57 [PATCH v3 00/17] ASoC: Intel: AVS - Audio DSP for cAVS Cezary Rojewski
                   ` (2 preceding siblings ...)
  2022-03-04 14:57 ` [PATCH v3 03/17] ASoC: Intel: Introduce AVS driver Cezary Rojewski
@ 2022-03-04 14:57 ` Cezary Rojewski
  2022-03-04 16:09   ` Ranjani Sridharan
  2022-03-04 14:57 ` [PATCH v3 05/17] ASoC: Intel: avs: Add code loading requests Cezary Rojewski
                   ` (12 subsequent siblings)
  16 siblings, 1 reply; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-04 14:57 UTC (permalink / raw)
  To: alsa-devel
  Cc: Cezary Rojewski, rad, upstream, harshapriya.n, tiwai,
	pierre-louis.bossart, hdegoede, broonie, amadeuszx.slawinski,
	cujomalainey, lma

Implement the IPC between Intel audio firmware and kernel driver. The
IPC allows transmission of requests, handling of responses as well as
unsolicited (i.e. firmware-generated) notifications.

A subscription mechanism is added to enable different parts of the
driver to register for specific notifications.

The part of the DSP boot process that involves sending ROM message
requires an extra step - must be followed by unstall operation of
MAIN_CORE. All other types of messages do not require such specific
handling, so separate set of functions is provided for sending these.

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       | 100 +++++++++
 sound/soc/intel/avs/ipc.c       | 387 ++++++++++++++++++++++++++++++++
 sound/soc/intel/avs/messages.h  | 170 ++++++++++++++
 sound/soc/intel/avs/registers.h |  45 ++++
 5 files changed, 703 insertions(+), 1 deletion(-)
 create mode 100644 sound/soc/intel/avs/ipc.c
 create mode 100644 sound/soc/intel/avs/messages.h

diff --git a/sound/soc/intel/avs/Makefile b/sound/soc/intel/avs/Makefile
index 5f7976a95fe2..e243806dd38a 100644
--- a/sound/soc/intel/avs/Makefile
+++ b/sound/soc/intel/avs/Makefile
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
-snd-soc-avs-objs := dsp.o
+snd-soc-avs-objs := dsp.o ipc.o
 
 obj-$(CONFIG_SND_SOC_INTEL_AVS) += snd-soc-avs.o
diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h
index d4e6310e4bf7..841b8541b101 100644
--- a/sound/soc/intel/avs/avs.h
+++ b/sound/soc/intel/avs/avs.h
@@ -11,13 +11,27 @@
 
 #include <linux/device.h>
 #include <sound/hda_codec.h>
+#include "messages.h"
 
 struct avs_dev;
 
+/*
+ * struct avs_dsp_ops - Platform-specific DSP operations
+ *
+ * @power: Power on or off DSP cores
+ * @reset: Enter or exit reset state on DSP cores
+ * @stall: Stall or run DSP cores
+ * @irq_handler: Top half of IPC servicing
+ * @irq_thread: Bottom half of IPC servicing
+ * @int_control: Enable or disable IPC interrupts
+ */
 struct avs_dsp_ops {
 	int (* const power)(struct avs_dev *, u32, bool);
 	int (* const reset)(struct avs_dev *, u32, bool);
 	int (* const stall)(struct avs_dev *, u32, bool);
+	irqreturn_t (* const irq_handler)(int, void *);
+	irqreturn_t (* const irq_thread)(int, void *);
+	void (* const int_control)(struct avs_dev *, bool);
 };
 
 #define avs_dsp_op(adev, op, ...) \
@@ -34,6 +48,9 @@ struct avs_spec {
 
 	const u32 core_init_mask;	/* used during DSP boot */
 	const u64 attributes;		/* bitmask of AVS_PLATATTR_* */
+	const u32 sram_base_offset;
+	const u32 sram_window_size;
+	const u32 rom_status;
 };
 
 /*
@@ -49,6 +66,9 @@ struct avs_dev {
 
 	void __iomem *dsp_ba;
 	const struct avs_spec *spec;
+	struct avs_ipc *ipc;
+
+	struct completion fw_ready;
 };
 
 /* from hda_bus to avs_dev */
@@ -68,4 +88,84 @@ int avs_dsp_core_stall(struct avs_dev *adev, u32 core_mask, bool stall);
 int avs_dsp_core_enable(struct avs_dev *adev, u32 core_mask);
 int avs_dsp_core_disable(struct avs_dev *adev, u32 core_mask);
 
+/* Inter Process Communication */
+
+struct avs_ipc_msg {
+	union {
+		u64 header;
+		union avs_global_msg glb;
+		union avs_reply_msg rsp;
+	};
+	void *data;
+	size_t size;
+};
+
+/*
+ * struct avs_ipc - DSP IPC context
+ *
+ * @dev: PCI device
+ * @rx: Reply message cache
+ * @default_timeout_ms: default message timeout in MS
+ * @ready: whether firmware is ready and communication is open
+ * @rx_completed: whether RX for previously sent TX has been received
+ * @rx_lock: for serializating manipulation of rx_* fields
+ * @msg_lock: for synchronizing request handling
+ * @done_completion: DONE-part of IPC i.e. ROM and ACKs from FW
+ * @busy_completion: BUSY-part of IPC i.e. receiving responses from FW
+ */
+struct avs_ipc {
+	struct device *dev;
+
+	struct avs_ipc_msg rx;
+	u32 default_timeout_ms;
+	bool ready;
+
+	bool rx_completed;
+	spinlock_t rx_lock;
+	struct mutex msg_mutex;
+	struct completion done_completion;
+	struct completion busy_completion;
+};
+
+#define AVS_EIPC	EREMOTEIO
+/*
+ * IPC handlers may return positive value (firmware error code) what denotes
+ * successful HOST <-> DSP communication yet failure to process specific request.
+ *
+ * Below macro converts returned value to linux kernel error code.
+ * All IPC callers MUST use it as soon as firmware error code is consumed.
+ */
+#define AVS_IPC_RET(ret) \
+	(((ret) <= 0) ? (ret) : -AVS_EIPC)
+
+static inline void avs_ipc_err(struct avs_dev *adev, struct avs_ipc_msg *tx,
+			       const char *name, int error)
+{
+	/*
+	 * If IPC channel is blocked e.g.: due to ongoing recovery,
+	 * -EPERM error code is expected and thus it's not an actual error.
+	 */
+	if (error == -EPERM)
+		dev_dbg(adev->dev, "%s 0x%08x 0x%08x failed: %d\n", name,
+			tx->glb.primary, tx->glb.ext.val, error);
+	else
+		dev_err(adev->dev, "%s 0x%08x 0x%08x failed: %d\n", name,
+			tx->glb.primary, tx->glb.ext.val, error);
+}
+
+irqreturn_t avs_dsp_irq_handler(int irq, void *dev_id);
+irqreturn_t avs_dsp_irq_thread(int irq, void *dev_id);
+void avs_dsp_process_response(struct avs_dev *adev, u64 header);
+int avs_dsp_send_msg_timeout(struct avs_dev *adev,
+			     struct avs_ipc_msg *request,
+			     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);
+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);
+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);
+
 #endif /* __SOUND_SOC_INTEL_AVS_H */
diff --git a/sound/soc/intel/avs/ipc.c b/sound/soc/intel/avs/ipc.c
new file mode 100644
index 000000000000..c0722f8b195f
--- /dev/null
+++ b/sound/soc/intel/avs/ipc.c
@@ -0,0 +1,387 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/slab.h>
+#include <sound/hdaudio_ext.h>
+#include "avs.h"
+#include "messages.h"
+#include "registers.h"
+
+#define AVS_IPC_TIMEOUT_MS	300
+
+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);
+
+	ipc->rx.header = header;
+	/* Abort copying payload if request processing was unsuccessful. */
+	if (!msg.status)
+		memcpy_fromio(ipc->rx.data, avs_uplink_addr(adev),
+			      ipc->rx.size);
+}
+
+static void avs_dsp_process_notification(struct avs_dev *adev, u64 header)
+{
+	struct avs_notify_mod_data mod_data;
+	union avs_notify_msg msg = AVS_MSG(header);
+	size_t data_size = 0;
+	void *data = NULL;
+
+	/* Ignore spurious notifications until handshake is established. */
+	if (!adev->ipc->ready && msg.notify_msg_type != AVS_NOTIFY_FW_READY) {
+		dev_dbg(adev->dev, "FW not ready, skip notification: 0x%08x\n",
+			msg.primary);
+		return;
+	}
+
+	/* Calculate notification payload size. */
+	switch (msg.notify_msg_type) {
+	case AVS_NOTIFY_FW_READY:
+		break;
+
+	case AVS_NOTIFY_PHRASE_DETECTED:
+		data_size = sizeof(struct avs_notify_voice_data);
+		break;
+
+	case AVS_NOTIFY_RESOURCE_EVENT:
+		data_size = sizeof(struct avs_notify_res_data);
+		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));
+		data_size = sizeof(mod_data) + mod_data.data_size;
+		break;
+
+	default:
+		dev_info(adev->dev, "unknown notification: 0x%08x\n",
+			 msg.primary);
+		break;
+	}
+
+	if (data_size) {
+		data = kmalloc(data_size, GFP_KERNEL);
+		if (!data)
+			return;
+
+		memcpy_fromio(data, avs_uplink_addr(adev), data_size);
+	}
+
+	/* Perform notification-specific operations. */
+	switch (msg.notify_msg_type) {
+	case AVS_NOTIFY_FW_READY:
+		dev_dbg(adev->dev, "FW READY 0x%08x\n", msg.primary);
+		adev->ipc->ready = true;
+		complete(&adev->fw_ready);
+		break;
+
+	default:
+		break;
+	}
+
+	kfree(data);
+}
+
+void avs_dsp_process_response(struct avs_dev *adev, u64 header)
+{
+	struct avs_ipc *ipc = adev->ipc;
+
+	/*
+	 * Response may either be solicited - a reply for a request that has
+	 * been sent beforehand - or unsolicited (notification).
+	 */
+	if (avs_msg_is_reply(header)) {
+		/* Response processing is invoked from IRQ thread. */
+		spin_lock_irq(&ipc->rx_lock);
+		avs_dsp_receive_rx(adev, header);
+		ipc->rx_completed = true;
+		spin_unlock_irq(&ipc->rx_lock);
+	} else {
+		avs_dsp_process_notification(adev, header);
+	}
+
+	complete(&ipc->busy_completion);
+}
+
+irqreturn_t avs_dsp_irq_handler(int irq, void *dev_id)
+{
+	struct avs_dev *adev = dev_id;
+	struct avs_ipc *ipc = adev->ipc;
+	u32 adspis, hipc_rsp, hipc_ack;
+	irqreturn_t ret = IRQ_NONE;
+
+	adspis = snd_hdac_adsp_readl(adev, AVS_ADSP_REG_ADSPIS);
+	if (adspis == UINT_MAX || !(adspis & AVS_ADSP_ADSPIS_IPC))
+		return ret;
+
+	hipc_ack = snd_hdac_adsp_readl(adev, SKL_ADSP_REG_HIPCIE);
+	hipc_rsp = snd_hdac_adsp_readl(adev, SKL_ADSP_REG_HIPCT);
+
+	/* DSP acked host's request */
+	if (hipc_ack & SKL_ADSP_HIPCIE_DONE) {
+		/*
+		 * As an extra precaution, mask done interrupt. Code executed
+		 * due to complete() found below does not assume any masking.
+		 */
+		snd_hdac_adsp_updatel(adev, SKL_ADSP_REG_HIPCCTL,
+				      AVS_ADSP_HIPCCTL_DONE, 0);
+
+		complete(&ipc->done_completion);
+
+		/* tell DSP it has our attention */
+		snd_hdac_adsp_updatel(adev, SKL_ADSP_REG_HIPCIE,
+				      SKL_ADSP_HIPCIE_DONE,
+				      SKL_ADSP_HIPCIE_DONE);
+		/* unmask done interrupt */
+		snd_hdac_adsp_updatel(adev, SKL_ADSP_REG_HIPCCTL,
+				      AVS_ADSP_HIPCCTL_DONE,
+				      AVS_ADSP_HIPCCTL_DONE);
+		ret = IRQ_HANDLED;
+	}
+
+	/* DSP sent new response to process */
+	if (hipc_rsp & SKL_ADSP_HIPCT_BUSY) {
+		/* mask busy interrupt */
+		snd_hdac_adsp_updatel(adev, SKL_ADSP_REG_HIPCCTL,
+				      AVS_ADSP_HIPCCTL_BUSY, 0);
+
+		ret = IRQ_WAKE_THREAD;
+	}
+
+	return ret;
+}
+
+irqreturn_t avs_dsp_irq_thread(int irq, void *dev_id)
+{
+	struct avs_dev *adev = dev_id;
+	union avs_reply_msg msg;
+	u32 hipct, hipcte;
+
+	hipct = snd_hdac_adsp_readl(adev, SKL_ADSP_REG_HIPCT);
+	hipcte = snd_hdac_adsp_readl(adev, SKL_ADSP_REG_HIPCTE);
+
+	/* ensure DSP sent new response to process */
+	if (!(hipct & SKL_ADSP_HIPCT_BUSY))
+		return IRQ_NONE;
+
+	msg.primary = hipct;
+	msg.ext.val = hipcte;
+	avs_dsp_process_response(adev, msg.val);
+
+	/* tell DSP we accepted its message */
+	snd_hdac_adsp_updatel(adev, SKL_ADSP_REG_HIPCT,
+			      SKL_ADSP_HIPCT_BUSY, SKL_ADSP_HIPCT_BUSY);
+	/* unmask busy interrupt */
+	snd_hdac_adsp_updatel(adev, SKL_ADSP_REG_HIPCCTL,
+			      AVS_ADSP_HIPCCTL_BUSY, AVS_ADSP_HIPCCTL_BUSY);
+
+	return IRQ_HANDLED;
+}
+
+static bool avs_ipc_is_busy(struct avs_ipc *ipc)
+{
+	struct avs_dev *adev = to_avs_dev(ipc->dev);
+	u32 hipc_rsp;
+
+	hipc_rsp = snd_hdac_adsp_readl(adev, SKL_ADSP_REG_HIPCT);
+	return hipc_rsp & SKL_ADSP_HIPCT_BUSY;
+}
+
+static int avs_ipc_wait_busy_completion(struct avs_ipc *ipc, int timeout)
+{
+	u32 repeats_left = 128; /* to avoid infinite looping */
+	int ret;
+
+again:
+	ret = wait_for_completion_timeout(&ipc->busy_completion,
+					  msecs_to_jiffies(timeout));
+
+	/* DSP could be unresponsive at this point. */
+	if (!ipc->ready)
+		return -EPERM;
+
+	if (!ret) {
+		if (!avs_ipc_is_busy(ipc))
+			return -ETIMEDOUT;
+		/*
+		 * Firmware did its job, either notification or reply
+		 * has been received - now wait until it's processed.
+		 */
+		wait_for_completion_killable(&ipc->busy_completion);
+	}
+
+	/* Ongoing notification's bottom-half may cause early wakeup */
+	spin_lock(&ipc->rx_lock);
+	if (!ipc->rx_completed) {
+		if (repeats_left) {
+			/* Reply delayed due to notification. */
+			repeats_left--;
+			reinit_completion(&ipc->busy_completion);
+			spin_unlock(&ipc->rx_lock);
+			goto again;
+		}
+
+		spin_unlock(&ipc->rx_lock);
+		return -ETIMEDOUT;
+	}
+
+	spin_unlock(&ipc->rx_lock);
+	return 0;
+}
+
+static void avs_ipc_msg_init(struct avs_ipc *ipc, struct avs_ipc_msg *reply)
+{
+	lockdep_assert_held(&ipc->rx_lock);
+
+	ipc->rx.header = 0;
+	ipc->rx.size = reply ? reply->size : 0;
+	ipc->rx_completed = false;
+
+	reinit_completion(&ipc->done_completion);
+	reinit_completion(&ipc->busy_completion);
+}
+
+static void avs_dsp_send_tx(struct avs_dev *adev, struct avs_ipc_msg *tx)
+{
+	tx->header |= SKL_ADSP_HIPCI_BUSY;
+
+	if (tx->size)
+		memcpy_toio(avs_downlink_addr(adev), tx->data, tx->size);
+	snd_hdac_adsp_writel(adev, SKL_ADSP_REG_HIPCIE, tx->header >> 32);
+	snd_hdac_adsp_writel(adev, SKL_ADSP_REG_HIPCI, tx->header & UINT_MAX);
+}
+
+static int avs_dsp_do_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request,
+			       struct avs_ipc_msg *reply, int timeout)
+{
+	struct avs_ipc *ipc = adev->ipc;
+	int ret;
+
+	if (!ipc->ready)
+		return -EPERM;
+
+	mutex_lock(&ipc->msg_mutex);
+
+	spin_lock(&ipc->rx_lock);
+	avs_ipc_msg_init(ipc, reply);
+	avs_dsp_send_tx(adev, request);
+	spin_unlock(&ipc->rx_lock);
+
+	ret = avs_ipc_wait_busy_completion(ipc, timeout);
+	if (ret) {
+		if (ret == -ETIMEDOUT) {
+			dev_crit(adev->dev, "communication severed: %d, rebooting dsp..\n",
+				 ret);
+
+			avs_ipc_block(ipc);
+		}
+		goto exit;
+	}
+
+	ret = ipc->rx.rsp.status;
+	if (reply) {
+		reply->header = ipc->rx.header;
+		if (reply->data && ipc->rx.size)
+			memcpy(reply->data, ipc->rx.data, reply->size);
+	}
+
+exit:
+	mutex_unlock(&ipc->msg_mutex);
+	return ret;
+}
+
+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);
+}
+
+int avs_dsp_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request,
+		     struct avs_ipc_msg *reply)
+{
+	return avs_dsp_send_msg_timeout(adev, request, reply,
+					adev->ipc->default_timeout_ms);
+}
+
+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;
+	int ret;
+
+	mutex_lock(&ipc->msg_mutex);
+
+	spin_lock(&ipc->rx_lock);
+	avs_ipc_msg_init(ipc, NULL);
+	avs_dsp_send_tx(adev, request);
+	spin_unlock(&ipc->rx_lock);
+
+	/* ROM messages must be sent before main core is unstalled */
+	ret = avs_dsp_op(adev, stall, AVS_MAIN_CORE_MASK, false);
+	if (!ret) {
+		ret = wait_for_completion_timeout(&ipc->done_completion,
+						  msecs_to_jiffies(timeout));
+		ret = ret ? 0 : -ETIMEDOUT;
+	}
+
+	mutex_unlock(&ipc->msg_mutex);
+
+	return ret;
+}
+
+int avs_dsp_send_rom_msg_timeout(struct avs_dev *adev,
+				 struct avs_ipc_msg *request, int timeout)
+{
+	return avs_dsp_do_send_rom_msg(adev, request, timeout);
+}
+
+int avs_dsp_send_rom_msg(struct avs_dev *adev, struct avs_ipc_msg *request)
+{
+	return avs_dsp_send_rom_msg_timeout(adev, request,
+					    adev->ipc->default_timeout_ms);
+}
+
+void avs_dsp_interrupt_control(struct avs_dev *adev, bool enable)
+{
+	u32 value, mask;
+
+	/*
+	 * No particular bit setting order. All of these are required
+	 * to have a functional SW <-> FW communication.
+	 */
+	value = enable ? AVS_ADSP_ADSPIC_IPC : 0;
+	snd_hdac_adsp_updatel(adev, AVS_ADSP_REG_ADSPIC,
+			      AVS_ADSP_ADSPIC_IPC, value);
+
+	mask = AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY;
+	value = enable ? mask : 0;
+	snd_hdac_adsp_updatel(adev, SKL_ADSP_REG_HIPCCTL, mask, value);
+}
+
+int avs_ipc_init(struct avs_ipc *ipc, struct device *dev)
+{
+	ipc->rx.data = devm_kzalloc(dev, AVS_MAILBOX_SIZE, GFP_KERNEL);
+	if (!ipc->rx.data)
+		return -ENOMEM;
+
+	ipc->dev = dev;
+	ipc->ready = false;
+	ipc->default_timeout_ms = AVS_IPC_TIMEOUT_MS;
+	init_completion(&ipc->done_completion);
+	init_completion(&ipc->busy_completion);
+	spin_lock_init(&ipc->rx_lock);
+	mutex_init(&ipc->msg_mutex);
+
+	return 0;
+}
+
+void avs_ipc_block(struct avs_ipc *ipc)
+{
+	ipc->ready = false;
+}
diff --git a/sound/soc/intel/avs/messages.h b/sound/soc/intel/avs/messages.h
new file mode 100644
index 000000000000..003e634f5547
--- /dev/null
+++ b/sound/soc/intel/avs/messages.h
@@ -0,0 +1,170 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright(c) 2021 Intel Corporation. All rights reserved.
+ *
+ * Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+ *          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+ */
+
+#ifndef __SOUND_SOC_INTEL_AVS_MSGS_H
+#define __SOUND_SOC_INTEL_AVS_MSGS_H
+
+struct avs_dev;
+
+#define AVS_MAILBOX_SIZE 4096
+
+enum avs_msg_target {
+	AVS_FW_GEN_MSG = 0,
+	AVS_MOD_MSG = 1
+};
+
+enum avs_msg_direction {
+	AVS_MSG_REQUEST = 0,
+	AVS_MSG_REPLY = 1
+};
+
+enum avs_global_msg_type {
+	AVS_GLB_NOTIFICATION = 27,
+};
+
+union avs_global_msg {
+	u64 val;
+	struct {
+		union {
+			u32 primary;
+			struct {
+				u32 rsvd:24;
+				u32 global_msg_type:5;
+				u32 msg_direction:1;
+				u32 msg_target:1;
+			};
+		};
+		union {
+			u32 val;
+		} ext;
+	};
+} __packed;
+
+struct avs_tlv {
+	u32 type;
+	u32 length;
+	u32 value[];
+} __packed;
+
+union avs_module_msg {
+	u64 val;
+	struct {
+		union {
+			u32 primary;
+			struct {
+				u32 module_id:16;
+				u32 instance_id:8;
+				u32 module_msg_type:5;
+				u32 msg_direction:1;
+				u32 msg_target:1;
+			};
+		};
+		union {
+			u32 val;
+		} ext;
+	};
+} __packed;
+
+union avs_reply_msg {
+	u64 val;
+	struct {
+		union {
+			u32 primary;
+			struct {
+				u32 status:24;
+				u32 global_msg_type:5;
+				u32 msg_direction:1;
+				u32 msg_target:1;
+			};
+		};
+		union {
+			u32 val;
+		} ext;
+	};
+} __packed;
+
+enum avs_notify_msg_type {
+	AVS_NOTIFY_PHRASE_DETECTED = 4,
+	AVS_NOTIFY_RESOURCE_EVENT = 5,
+	AVS_NOTIFY_FW_READY = 8,
+	AVS_NOTIFY_MODULE_EVENT = 12,
+};
+
+union avs_notify_msg {
+	u64 val;
+	struct {
+		union {
+			u32 primary;
+			struct {
+				u32 rsvd:16;
+				u32 notify_msg_type:8;
+				u32 global_msg_type:5;
+				u32 msg_direction:1;
+				u32 msg_target:1;
+			};
+		};
+		union {
+			u32 val;
+		} ext;
+	};
+} __packed;
+
+#define AVS_MSG(hdr) { .val = hdr }
+
+#define AVS_GLOBAL_REQUEST(msg_type)		\
+{						\
+	.global_msg_type = AVS_GLB_##msg_type,	\
+	.msg_direction = AVS_MSG_REQUEST,	\
+	.msg_target = AVS_FW_GEN_MSG,		\
+}
+
+#define AVS_MODULE_REQUEST(msg_type)		\
+{						\
+	.module_msg_type = AVS_MOD_##msg_type,	\
+	.msg_direction = AVS_MSG_REQUEST,	\
+	.msg_target = AVS_MOD_MSG,		\
+}
+
+#define AVS_NOTIFICATION(msg_type)		\
+{						\
+	.notify_msg_type = AVS_NOTIFY_##msg_type,\
+	.global_msg_type = AVS_GLB_NOTIFICATION,\
+	.msg_direction = AVS_MSG_REPLY,		\
+	.msg_target = AVS_FW_GEN_MSG,		\
+}
+
+#define avs_msg_is_reply(hdr) \
+({ \
+	union avs_reply_msg __msg = AVS_MSG(hdr); \
+	__msg.msg_direction == AVS_MSG_REPLY && \
+	__msg.global_msg_type != AVS_GLB_NOTIFICATION; \
+})
+
+/* Notification types */
+
+struct avs_notify_voice_data {
+	u16 kpd_score;
+	u16 reserved;
+} __packed;
+
+struct avs_notify_res_data {
+	u32 resource_type;
+	u32 resource_id;
+	u32 event_type;
+	u32 reserved;
+	u32 data[6];
+} __packed;
+
+struct avs_notify_mod_data {
+	u32 module_instance_id;
+	u32 event_id;
+	u32 data_size;
+	u32 data[];
+} __packed;
+
+#endif /* __SOUND_SOC_INTEL_AVS_MSGS_H */
diff --git a/sound/soc/intel/avs/registers.h b/sound/soc/intel/avs/registers.h
index e0b6c8ffe633..4bb10ca46a1e 100644
--- a/sound/soc/intel/avs/registers.h
+++ b/sound/soc/intel/avs/registers.h
@@ -12,6 +12,11 @@
 /* Intel HD Audio General DSP Registers */
 #define AVS_ADSP_GEN_BASE		0x0
 #define AVS_ADSP_REG_ADSPCS		(AVS_ADSP_GEN_BASE + 0x04)
+#define AVS_ADSP_REG_ADSPIC		(AVS_ADSP_GEN_BASE + 0x08)
+#define AVS_ADSP_REG_ADSPIS		(AVS_ADSP_GEN_BASE + 0x0C)
+
+#define AVS_ADSP_ADSPIC_IPC		BIT(0)
+#define AVS_ADSP_ADSPIS_IPC		BIT(0)
 
 #define AVS_ADSPCS_CRST_MASK(cm)	(cm)
 #define AVS_ADSPCS_CSTALL_MASK(cm)	((cm) << 8)
@@ -19,4 +24,44 @@
 #define AVS_ADSPCS_CPA_MASK(cm)		((cm) << 24)
 #define AVS_MAIN_CORE_MASK		BIT(0)
 
+#define AVS_ADSP_HIPCCTL_BUSY		BIT(0)
+#define AVS_ADSP_HIPCCTL_DONE		BIT(1)
+
+/* SKL Intel HD Audio Inter-Processor Communication Registers */
+#define SKL_ADSP_IPC_BASE		0x40
+#define SKL_ADSP_REG_HIPCT		(SKL_ADSP_IPC_BASE + 0x00)
+#define SKL_ADSP_REG_HIPCTE		(SKL_ADSP_IPC_BASE + 0x04)
+#define SKL_ADSP_REG_HIPCI		(SKL_ADSP_IPC_BASE + 0x08)
+#define SKL_ADSP_REG_HIPCIE		(SKL_ADSP_IPC_BASE + 0x0C)
+#define SKL_ADSP_REG_HIPCCTL		(SKL_ADSP_IPC_BASE + 0x10)
+
+#define SKL_ADSP_HIPCI_BUSY		BIT(31)
+#define SKL_ADSP_HIPCIE_DONE		BIT(30)
+#define SKL_ADSP_HIPCT_BUSY		BIT(31)
+
+/* 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)
+#define AVS_FW_REG_ERROR_CODE(adev)	(AVS_FW_REG_BASE(adev) + 0x4)
+
+#define AVS_FW_REGS_SIZE		PAGE_SIZE
+#define AVS_FW_REGS_WINDOW		0
+/* DSP -> HOST communication window */
+#define AVS_UPLINK_WINDOW		AVS_FW_REGS_WINDOW
+/* HOST -> DSP communication window */
+#define AVS_DOWNLINK_WINDOW		1
+
+/* registry I/O helpers */
+#define avs_sram_offset(adev, window_idx) \
+	((adev)->spec->sram_base_offset + \
+	 (adev)->spec->sram_window_size * (window_idx))
+
+#define avs_sram_addr(adev, window_idx) \
+	((adev)->dsp_ba + avs_sram_offset(adev, window_idx))
+
+#define avs_uplink_addr(adev) \
+	(avs_sram_addr(adev, AVS_UPLINK_WINDOW) + AVS_FW_REGS_SIZE)
+#define avs_downlink_addr(adev) \
+	avs_sram_addr(adev, AVS_DOWNLINK_WINDOW)
+
 #endif /* __SOUND_SOC_INTEL_AVS_REGS_H */
-- 
2.25.1


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

* [PATCH v3 05/17] ASoC: Intel: avs: Add code loading requests
  2022-03-04 14:57 [PATCH v3 00/17] ASoC: Intel: AVS - Audio DSP for cAVS Cezary Rojewski
                   ` (3 preceding siblings ...)
  2022-03-04 14:57 ` [PATCH v3 04/17] ASoC: Intel: avs: Inter process communication Cezary Rojewski
@ 2022-03-04 14:57 ` Cezary Rojewski
  2022-03-04 14:57 ` [PATCH v3 06/17] ASoC: Intel: avs: Add pipeline management requests Cezary Rojewski
                   ` (11 subsequent siblings)
  16 siblings, 0 replies; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-04 14:57 UTC (permalink / raw)
  To: alsa-devel
  Cc: Cezary Rojewski, rad, upstream, harshapriya.n, tiwai,
	pierre-louis.bossart, hdegoede, broonie, amadeuszx.slawinski,
	cujomalainey, lma

Before firmware and its modules can be used, they have to be loaded.
Code loading process is complex and is a combination of DMA and IPC
operations. Here, IPC part is being added and accounts for CLDMA and HDA
mechanisms both.

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/messages.c | 65 ++++++++++++++++++++++++++++++++++
 sound/soc/intel/avs/messages.h | 22 ++++++++++++
 3 files changed, 88 insertions(+), 1 deletion(-)
 create mode 100644 sound/soc/intel/avs/messages.c

diff --git a/sound/soc/intel/avs/Makefile b/sound/soc/intel/avs/Makefile
index e243806dd38a..c0824f30fd3b 100644
--- a/sound/soc/intel/avs/Makefile
+++ b/sound/soc/intel/avs/Makefile
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
-snd-soc-avs-objs := dsp.o ipc.o
+snd-soc-avs-objs := dsp.o ipc.o messages.o
 
 obj-$(CONFIG_SND_SOC_INTEL_AVS) += snd-soc-avs.o
diff --git a/sound/soc/intel/avs/messages.c b/sound/soc/intel/avs/messages.c
new file mode 100644
index 000000000000..d568338b0737
--- /dev/null
+++ b/sound/soc/intel/avs/messages.c
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include "avs.h"
+#include "messages.h"
+
+#define AVS_CL_TIMEOUT_MS	5000
+
+int avs_ipc_load_modules(struct avs_dev *adev, u16 *mod_ids, u32 num_mod_ids)
+{
+	union avs_global_msg msg = AVS_GLOBAL_REQUEST(LOAD_MULTIPLE_MODULES);
+	struct avs_ipc_msg request;
+	int ret;
+
+	msg.load_multi_mods.mod_cnt = num_mod_ids;
+	request.header = msg.val;
+	request.data = mod_ids;
+	request.size = sizeof(*mod_ids) * num_mod_ids;
+
+	ret = avs_dsp_send_msg_timeout(adev, &request, NULL, AVS_CL_TIMEOUT_MS);
+	if (ret)
+		avs_ipc_err(adev, &request, "load multiple modules", ret);
+
+	return ret;
+}
+
+int avs_ipc_unload_modules(struct avs_dev *adev, u16 *mod_ids, u32 num_mod_ids)
+{
+	union avs_global_msg msg = AVS_GLOBAL_REQUEST(UNLOAD_MULTIPLE_MODULES);
+	struct avs_ipc_msg request;
+	int ret;
+
+	msg.load_multi_mods.mod_cnt = num_mod_ids;
+	request.header = msg.val;
+	request.data = mod_ids;
+	request.size = sizeof(*mod_ids) * num_mod_ids;
+
+	ret = avs_dsp_send_msg_timeout(adev, &request, NULL, AVS_CL_TIMEOUT_MS);
+	if (ret)
+		avs_ipc_err(adev, &request, "unload multiple modules", ret);
+
+	return ret;
+}
+
+int avs_ipc_load_library(struct avs_dev *adev, u32 dma_id, u32 lib_id)
+{
+	union avs_global_msg msg = AVS_GLOBAL_REQUEST(LOAD_LIBRARY);
+	struct avs_ipc_msg request = {{0}};
+	int ret;
+
+	msg.load_lib.dma_id = dma_id;
+	msg.load_lib.lib_id = lib_id;
+	request.header = msg.val;
+
+	ret = avs_dsp_send_msg_timeout(adev, &request, NULL, AVS_CL_TIMEOUT_MS);
+	if (ret)
+		avs_ipc_err(adev, &request, "load library", ret);
+
+	return ret;
+}
diff --git a/sound/soc/intel/avs/messages.h b/sound/soc/intel/avs/messages.h
index 003e634f5547..b9ec1c64179b 100644
--- a/sound/soc/intel/avs/messages.h
+++ b/sound/soc/intel/avs/messages.h
@@ -24,6 +24,9 @@ enum avs_msg_direction {
 };
 
 enum avs_global_msg_type {
+	AVS_GLB_LOAD_MULTIPLE_MODULES = 15,
+	AVS_GLB_UNLOAD_MULTIPLE_MODULES = 16,
+	AVS_GLB_LOAD_LIBRARY = 24,
 	AVS_GLB_NOTIFICATION = 27,
 };
 
@@ -38,6 +41,16 @@ union avs_global_msg {
 				u32 msg_direction:1;
 				u32 msg_target:1;
 			};
+			/* module loading */
+			struct {
+				u32 mod_cnt:8;
+			} load_multi_mods;
+			/* library loading */
+			struct {
+				u32 dma_id:5;
+				u32 rsvd:11;
+				u32 lib_id:4;
+			} load_lib;
 		};
 		union {
 			u32 val;
@@ -84,6 +97,10 @@ union avs_reply_msg {
 		};
 		union {
 			u32 val;
+			/* module loading */
+			struct {
+				u32 err_mod_id:16;
+			} load_multi_mods;
 		} ext;
 	};
 } __packed;
@@ -167,4 +184,9 @@ struct avs_notify_mod_data {
 	u32 data[];
 } __packed;
 
+/* Code loading messages */
+int avs_ipc_load_modules(struct avs_dev *adev, u16 *mod_ids, u32 num_mod_ids);
+int avs_ipc_unload_modules(struct avs_dev *adev, u16 *mod_ids, u32 num_mod_ids);
+int avs_ipc_load_library(struct avs_dev *adev, u32 dma_id, u32 lib_id);
+
 #endif /* __SOUND_SOC_INTEL_AVS_MSGS_H */
-- 
2.25.1


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

* [PATCH v3 06/17] ASoC: Intel: avs: Add pipeline management requests
  2022-03-04 14:57 [PATCH v3 00/17] ASoC: Intel: AVS - Audio DSP for cAVS Cezary Rojewski
                   ` (4 preceding siblings ...)
  2022-03-04 14:57 ` [PATCH v3 05/17] ASoC: Intel: avs: Add code loading requests Cezary Rojewski
@ 2022-03-04 14:57 ` Cezary Rojewski
  2022-03-04 16:13   ` Ranjani Sridharan
  2022-03-04 14:57 ` [PATCH v3 07/17] ASoC: Intel: avs: Add module " Cezary Rojewski
                   ` (10 subsequent siblings)
  16 siblings, 1 reply; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-04 14:57 UTC (permalink / raw)
  To: alsa-devel
  Cc: Cezary Rojewski, rad, upstream, harshapriya.n, tiwai,
	pierre-louis.bossart, hdegoede, broonie, amadeuszx.slawinski,
	cujomalainey, lma

Pipeline represents a scheduling entity. Their existence as well as
their state machine is controlled through CREATE_PIPELINE,
DELETE_PIPELINE and SET_PIPELINE_STATE IPCs.

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/messages.c | 76 ++++++++++++++++++++++++++++++++++
 sound/soc/intel/avs/messages.h | 48 +++++++++++++++++++++
 2 files changed, 124 insertions(+)

diff --git a/sound/soc/intel/avs/messages.c b/sound/soc/intel/avs/messages.c
index d568338b0737..de2d50f8c6b4 100644
--- a/sound/soc/intel/avs/messages.c
+++ b/sound/soc/intel/avs/messages.c
@@ -63,3 +63,79 @@ int avs_ipc_load_library(struct avs_dev *adev, u32 dma_id, u32 lib_id)
 
 	return ret;
 }
+
+int avs_ipc_create_pipeline(struct avs_dev *adev, u16 req_size, u8 priority,
+			    u8 instance_id, bool lp, u16 attributes)
+{
+	union avs_global_msg msg = AVS_GLOBAL_REQUEST(CREATE_PIPELINE);
+	struct avs_ipc_msg request = {{0}};
+	int ret;
+
+	msg.create_ppl.ppl_mem_size = req_size;
+	msg.create_ppl.ppl_priority = priority;
+	msg.create_ppl.instance_id = instance_id;
+	msg.ext.create_ppl.lp = lp;
+	msg.ext.create_ppl.attributes = attributes;
+	request.header = msg.val;
+
+	ret = avs_dsp_send_msg(adev, &request, NULL);
+	if (ret)
+		avs_ipc_err(adev, &request, "create pipeline", ret);
+
+	return ret;
+}
+
+int avs_ipc_delete_pipeline(struct avs_dev *adev, u8 instance_id)
+{
+	union avs_global_msg msg = AVS_GLOBAL_REQUEST(DELETE_PIPELINE);
+	struct avs_ipc_msg request = {{0}};
+	int ret;
+
+	msg.ppl.instance_id = instance_id;
+	request.header = msg.val;
+
+	ret = avs_dsp_send_msg(adev, &request, NULL);
+	if (ret)
+		avs_ipc_err(adev, &request, "delete pipeline", ret);
+
+	return ret;
+}
+
+int avs_ipc_set_pipeline_state(struct avs_dev *adev, u8 instance_id,
+			       enum avs_pipeline_state state)
+{
+	union avs_global_msg msg = AVS_GLOBAL_REQUEST(SET_PIPELINE_STATE);
+	struct avs_ipc_msg request = {{0}};
+	int ret;
+
+	msg.set_ppl_state.ppl_id = instance_id;
+	msg.set_ppl_state.state = state;
+	request.header = msg.val;
+
+	ret = avs_dsp_send_msg(adev, &request, NULL);
+	if (ret)
+		avs_ipc_err(adev, &request, "set pipeline state", ret);
+
+	return ret;
+}
+
+int avs_ipc_get_pipeline_state(struct avs_dev *adev, u8 instance_id,
+			       enum avs_pipeline_state *state)
+{
+	union avs_global_msg msg = AVS_GLOBAL_REQUEST(GET_PIPELINE_STATE);
+	struct avs_ipc_msg request = {{0}};
+	struct avs_ipc_msg reply = {{0}};
+	int ret;
+
+	msg.get_ppl_state.ppl_id = instance_id;
+	request.header = msg.val;
+
+	ret = avs_dsp_send_msg(adev, &request, &reply);
+	if (ret) {
+		avs_ipc_err(adev, &request, "get pipeline state", ret);
+		return ret;
+	}
+
+	*state = reply.rsp.ext.get_ppl_state.state;
+	return ret;
+}
diff --git a/sound/soc/intel/avs/messages.h b/sound/soc/intel/avs/messages.h
index b9ec1c64179b..c1bf1cff54d9 100644
--- a/sound/soc/intel/avs/messages.h
+++ b/sound/soc/intel/avs/messages.h
@@ -26,6 +26,10 @@ enum avs_msg_direction {
 enum avs_global_msg_type {
 	AVS_GLB_LOAD_MULTIPLE_MODULES = 15,
 	AVS_GLB_UNLOAD_MULTIPLE_MODULES = 16,
+	AVS_GLB_CREATE_PIPELINE = 17,
+	AVS_GLB_DELETE_PIPELINE = 18,
+	AVS_GLB_SET_PIPELINE_STATE = 19,
+	AVS_GLB_GET_PIPELINE_STATE = 20,
 	AVS_GLB_LOAD_LIBRARY = 24,
 	AVS_GLB_NOTIFICATION = 27,
 };
@@ -45,6 +49,23 @@ union avs_global_msg {
 			struct {
 				u32 mod_cnt:8;
 			} load_multi_mods;
+			/* pipeline management */
+			struct {
+				u32 ppl_mem_size:11;
+				u32 ppl_priority:5;
+				u32 instance_id:8;
+			} create_ppl;
+			struct {
+				u32 rsvd:16;
+				u32 instance_id:8;
+			} ppl; /* generic ppl request */
+			struct {
+				u32 state:16;
+				u32 ppl_id:8;
+			} set_ppl_state;
+			struct {
+				u32 ppl_id:8;
+			} get_ppl_state;
 			/* library loading */
 			struct {
 				u32 dma_id:5;
@@ -54,6 +75,12 @@ union avs_global_msg {
 		};
 		union {
 			u32 val;
+			/* pipeline management */
+			struct {
+				u32 lp:1; /* low power flag */
+				u32 rsvd:3;
+				u32 attributes:16; /* additional scheduling flags */
+			} create_ppl;
 		} ext;
 	};
 } __packed;
@@ -101,6 +128,10 @@ union avs_reply_msg {
 			struct {
 				u32 err_mod_id:16;
 			} load_multi_mods;
+			/* pipeline management */
+			struct {
+				u32 state:5;
+			} get_ppl_state;
 		} ext;
 	};
 } __packed;
@@ -189,4 +220,21 @@ int avs_ipc_load_modules(struct avs_dev *adev, u16 *mod_ids, u32 num_mod_ids);
 int avs_ipc_unload_modules(struct avs_dev *adev, u16 *mod_ids, u32 num_mod_ids);
 int avs_ipc_load_library(struct avs_dev *adev, u32 dma_id, u32 lib_id);
 
+/* Pipeline management messages */
+enum avs_pipeline_state {
+	AVS_PPL_STATE_INVALID,
+	AVS_PPL_STATE_UNINITIALIZED,
+	AVS_PPL_STATE_RESET,
+	AVS_PPL_STATE_PAUSED,
+	AVS_PPL_STATE_RUNNING,
+};
+
+int avs_ipc_create_pipeline(struct avs_dev *adev, u16 req_size, u8 priority,
+			    u8 instance_id, bool lp, u16 attributes);
+int avs_ipc_delete_pipeline(struct avs_dev *adev, u8 instance_id);
+int avs_ipc_set_pipeline_state(struct avs_dev *adev, u8 instance_id,
+			       enum avs_pipeline_state state);
+int avs_ipc_get_pipeline_state(struct avs_dev *adev, u8 instance_id,
+			       enum avs_pipeline_state *state);
+
 #endif /* __SOUND_SOC_INTEL_AVS_MSGS_H */
-- 
2.25.1


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

* [PATCH v3 07/17] ASoC: Intel: avs: Add module management requests
  2022-03-04 14:57 [PATCH v3 00/17] ASoC: Intel: AVS - Audio DSP for cAVS Cezary Rojewski
                   ` (5 preceding siblings ...)
  2022-03-04 14:57 ` [PATCH v3 06/17] ASoC: Intel: avs: Add pipeline management requests Cezary Rojewski
@ 2022-03-04 14:57 ` Cezary Rojewski
  2022-03-04 16:21   ` Ranjani Sridharan
  2022-03-04 14:57 ` [PATCH v3 08/17] ASoC: Intel: avs: Add power " Cezary Rojewski
                   ` (9 subsequent siblings)
  16 siblings, 1 reply; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-04 14:57 UTC (permalink / raw)
  To: alsa-devel
  Cc: Cezary Rojewski, rad, upstream, harshapriya.n, tiwai,
	pierre-louis.bossart, hdegoede, broonie, amadeuszx.slawinski,
	cujomalainey, lma

Firmware modules implement processing algorithms. Their lifecycle,
similarly to pipelines is being controlled by IPCs: initialization,
deletion and (un)binding.

Modules can be configured at runtime - runtime parameters. This is done
with help of LARGE_CONFIG IPCs: getter and setter.

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/ipc.c      |   8 +-
 sound/soc/intel/avs/messages.c | 262 +++++++++++++++++++++++++++++++++
 sound/soc/intel/avs/messages.h |  53 +++++++
 3 files changed, 322 insertions(+), 1 deletion(-)

diff --git a/sound/soc/intel/avs/ipc.c b/sound/soc/intel/avs/ipc.c
index c0722f8b195f..9770368a898e 100644
--- a/sound/soc/intel/avs/ipc.c
+++ b/sound/soc/intel/avs/ipc.c
@@ -21,9 +21,15 @@ static void avs_dsp_receive_rx(struct avs_dev *adev, u64 header)
 
 	ipc->rx.header = header;
 	/* Abort copying payload if request processing was unsuccessful. */
-	if (!msg.status)
+	if (!msg.status) {
+		/* update size in case of LARGE_CONFIG_GET */
+		if (msg.msg_target == AVS_MOD_MSG &&
+		    msg.global_msg_type == AVS_MOD_LARGE_CONFIG_GET)
+			ipc->rx.size = msg.ext.large_config.data_off_size;
+
 		memcpy_fromio(ipc->rx.data, avs_uplink_addr(adev),
 			      ipc->rx.size);
+	}
 }
 
 static void avs_dsp_process_notification(struct avs_dev *adev, u64 header)
diff --git a/sound/soc/intel/avs/messages.c b/sound/soc/intel/avs/messages.c
index de2d50f8c6b4..613c9452226d 100644
--- a/sound/soc/intel/avs/messages.c
+++ b/sound/soc/intel/avs/messages.c
@@ -6,6 +6,7 @@
 //          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
 //
 
+#include <linux/slab.h>
 #include "avs.h"
 #include "messages.h"
 
@@ -139,3 +140,264 @@ int avs_ipc_get_pipeline_state(struct avs_dev *adev, u8 instance_id,
 	*state = reply.rsp.ext.get_ppl_state.state;
 	return ret;
 }
+
+/*
+ * avs_ipc_init_instance - Initialize module instance
+ *
+ * @adev: Driver context
+ * @module_id: Module-type id
+ * @instance_id: Unique module instance id
+ * @ppl_id: Parent pipeline id
+ * @core_id: DSP core to allocate module on
+ * @domain: Processing domain (low latency or data processing)
+ * @param: Module-type specific configuration
+ * @param_size: Size of @param in bytes
+ *
+ * Argument verification, as well as pipeline state checks are done by the
+ * firmware.
+ *
+ * Note: @ppl_id and @core_id are independent of each other as single pipeline
+ * can be composed of module instances located on different DSP cores.
+ */
+int avs_ipc_init_instance(struct avs_dev *adev, u16 module_id, u8 instance_id,
+			  u8 ppl_id, u8 core_id, u8 domain,
+			  void *param, u32 param_size)
+{
+	union avs_module_msg msg = AVS_MODULE_REQUEST(INIT_INSTANCE);
+	struct avs_ipc_msg request;
+	int ret;
+
+	msg.module_id = module_id;
+	msg.instance_id = instance_id;
+	/* firmware expects size provided in dwords */
+	msg.ext.init_instance.param_block_size =
+			DIV_ROUND_UP(param_size, sizeof(u32));
+	msg.ext.init_instance.ppl_instance_id = ppl_id;
+	msg.ext.init_instance.core_id = core_id;
+	msg.ext.init_instance.proc_domain = domain;
+
+	request.header = msg.val;
+	request.data = param;
+	request.size = param_size;
+
+	ret = avs_dsp_send_msg(adev, &request, NULL);
+	if (ret)
+		avs_ipc_err(adev, &request, "init instance", ret);
+
+	return ret;
+}
+
+/*
+ * avs_ipc_delete_instance - Delete module instance
+ *
+ * @adev: Driver context
+ * @module_id: Module-type id
+ * @instance_id: Unique module instance id
+ *
+ * Argument verification, as well as pipeline state checks are done by the
+ * firmware.
+ *
+ * Note: only standalone modules i.e. without a parent pipeline shall be
+ * deleted using this IPC message. In all other cases, pipeline owning the
+ * modules peforms cleanup automatically when it is deleted.
+ */
+int avs_ipc_delete_instance(struct avs_dev *adev, u16 module_id, u8 instance_id)
+{
+	union avs_module_msg msg = AVS_MODULE_REQUEST(DELETE_INSTANCE);
+	struct avs_ipc_msg request = {{0}};
+	int ret;
+
+	msg.module_id = module_id;
+	msg.instance_id = instance_id;
+	request.header = msg.val;
+
+	ret = avs_dsp_send_msg(adev, &request, NULL);
+	if (ret)
+		avs_ipc_err(adev, &request, "delete instance", ret);
+
+	return ret;
+}
+
+/*
+ * avs_ipc_bind - Bind two module instances
+ *
+ * @adev: Driver context
+ * @module_id: Source module-type id
+ * @instance_id: Source module instance id
+ * @dst_module_id: Sink module-type id
+ * @dst_instance_id: Sink module instance id
+ * @dst_queue: Sink module pin to bind @src_queue with
+ * @src_queue: Source module pin to bind @dst_queue with
+ */
+int avs_ipc_bind(struct avs_dev *adev, u16 module_id, u8 instance_id,
+		 u16 dst_module_id, u8 dst_instance_id,
+		 u8 dst_queue, u8 src_queue)
+{
+	union avs_module_msg msg = AVS_MODULE_REQUEST(BIND);
+	struct avs_ipc_msg request = {{0}};
+	int ret;
+
+	msg.module_id = module_id;
+	msg.instance_id = instance_id;
+	msg.ext.bind_unbind.dst_module_id = dst_module_id;
+	msg.ext.bind_unbind.dst_instance_id = dst_instance_id;
+	msg.ext.bind_unbind.dst_queue = dst_queue;
+	msg.ext.bind_unbind.src_queue = src_queue;
+	request.header = msg.val;
+
+	ret = avs_dsp_send_msg(adev, &request, NULL);
+	if (ret)
+		avs_ipc_err(adev, &request, "bind modules", ret);
+
+	return ret;
+}
+
+/*
+ * avs_ipc_unbind - Unbind two module instances
+ *
+ * @adev: Driver context
+ * @module_id: Source module-type id
+ * @instance_id: Source module instance id
+ * @dst_module_id: Sink module-type id
+ * @dst_instance_id: Sink module instance id
+ * @dst_queue: Sink module pin to unbind @src_queue from
+ * @src_queue: Source module pin to unbind @dst_queue from
+ */
+int avs_ipc_unbind(struct avs_dev *adev, u16 module_id, u8 instance_id,
+		   u16 dst_module_id, u8 dst_instance_id,
+		   u8 dst_queue, u8 src_queue)
+{
+	union avs_module_msg msg = AVS_MODULE_REQUEST(UNBIND);
+	struct avs_ipc_msg request = {{0}};
+	int ret;
+
+	msg.module_id = module_id;
+	msg.instance_id = instance_id;
+	msg.ext.bind_unbind.dst_module_id = dst_module_id;
+	msg.ext.bind_unbind.dst_instance_id = dst_instance_id;
+	msg.ext.bind_unbind.dst_queue = dst_queue;
+	msg.ext.bind_unbind.src_queue = src_queue;
+	request.header = msg.val;
+
+	ret = avs_dsp_send_msg(adev, &request, NULL);
+	if (ret)
+		avs_ipc_err(adev, &request, "unbind modules", ret);
+
+	return ret;
+}
+
+static int __avs_ipc_set_large_config(struct avs_dev *adev, u16 module_id, u8 instance_id,
+				      u8 param_id, bool init_block, bool final_block,
+				      u8 *request_data, size_t request_size, size_t off_size)
+{
+	union avs_module_msg msg = AVS_MODULE_REQUEST(LARGE_CONFIG_SET);
+	struct avs_ipc_msg request;
+	int ret;
+
+	msg.module_id = module_id;
+	msg.instance_id = instance_id;
+	msg.ext.large_config.data_off_size = off_size;
+	msg.ext.large_config.large_param_id = param_id;
+	msg.ext.large_config.final_block = final_block;
+	msg.ext.large_config.init_block = init_block;
+
+	request.header = msg.val;
+	request.data = request_data;
+	request.size = request_size;
+
+	ret = avs_dsp_send_msg(adev, &request, NULL);
+	if (ret)
+		avs_ipc_err(adev, &request, "large config set", ret);
+
+	return ret;
+}
+
+int avs_ipc_set_large_config(struct avs_dev *adev, u16 module_id,
+			     u8 instance_id, u8 param_id,
+			     u8 *request, size_t request_size)
+{
+	size_t remaining, tx_size;
+	bool final;
+	int ret;
+
+	remaining = request_size;
+	tx_size = min_t(size_t, AVS_MAILBOX_SIZE, remaining);
+	final = (tx_size == remaining);
+
+	/* Initial request states total payload size. */
+	ret = __avs_ipc_set_large_config(adev, module_id, instance_id,
+					 param_id, 1, final, request, tx_size,
+					 request_size);
+	if (ret)
+		return ret;
+
+	remaining -= tx_size;
+
+	/* Loop the rest only when payload exceeds mailbox's size. */
+	while (remaining) {
+		size_t offset;
+
+		offset = request_size - remaining;
+		tx_size = min_t(size_t, AVS_MAILBOX_SIZE, remaining);
+		final = (tx_size == remaining);
+
+		ret = __avs_ipc_set_large_config(adev, module_id, instance_id,
+						 param_id, 0, final,
+						 request + offset, tx_size,
+						 offset);
+		if (ret)
+			return ret;
+
+		remaining -= tx_size;
+	}
+
+	return 0;
+}
+
+int avs_ipc_get_large_config(struct avs_dev *adev, u16 module_id, u8 instance_id,
+			     u8 param_id, u8 *request_data, size_t request_size,
+			     u8 **reply_data, size_t *reply_size)
+{
+	union avs_module_msg msg = AVS_MODULE_REQUEST(LARGE_CONFIG_GET);
+	struct avs_ipc_msg request;
+	struct avs_ipc_msg reply = {{0}};
+	size_t size;
+	void *buf;
+	int ret;
+
+	reply.data = kzalloc(AVS_MAILBOX_SIZE, GFP_KERNEL);
+	if (!reply.data)
+		return -ENOMEM;
+
+	msg.module_id = module_id;
+	msg.instance_id = instance_id;
+	msg.ext.large_config.data_off_size = request_size;
+	msg.ext.large_config.large_param_id = param_id;
+	/* final_block is always 0 on request. Updated by fw on reply. */
+	msg.ext.large_config.final_block = 0;
+	msg.ext.large_config.init_block = 1;
+
+	request.header = msg.val;
+	request.data = request_data;
+	request.size = request_size;
+	reply.size = AVS_MAILBOX_SIZE;
+
+	ret = avs_dsp_send_msg(adev, &request, &reply);
+	if (ret) {
+		avs_ipc_err(adev, &request, "large config get", ret);
+		kfree(reply.data);
+		return ret;
+	}
+
+	size = reply.rsp.ext.large_config.data_off_size;
+	buf = krealloc(reply.data, size, GFP_KERNEL);
+	if (!buf) {
+		kfree(reply.data);
+		return -ENOMEM;
+	}
+
+	*reply_data = buf;
+	*reply_size = size;
+
+	return 0;
+}
diff --git a/sound/soc/intel/avs/messages.h b/sound/soc/intel/avs/messages.h
index c1bf1cff54d9..e4b95b066d70 100644
--- a/sound/soc/intel/avs/messages.h
+++ b/sound/soc/intel/avs/messages.h
@@ -91,6 +91,15 @@ struct avs_tlv {
 	u32 value[];
 } __packed;
 
+enum avs_module_msg_type {
+	AVS_MOD_INIT_INSTANCE = 0,
+	AVS_MOD_LARGE_CONFIG_GET = 3,
+	AVS_MOD_LARGE_CONFIG_SET = 4,
+	AVS_MOD_BIND = 5,
+	AVS_MOD_UNBIND = 6,
+	AVS_MOD_DELETE_INSTANCE = 11,
+};
+
 union avs_module_msg {
 	u64 val;
 	struct {
@@ -106,6 +115,24 @@ union avs_module_msg {
 		};
 		union {
 			u32 val;
+			struct {
+				u32 param_block_size:16;
+				u32 ppl_instance_id:8;
+				u32 core_id:4;
+				u32 proc_domain:1;
+			} init_instance;
+			struct {
+				u32 data_off_size:20;
+				u32 large_param_id:8;
+				u32 final_block:1;
+				u32 init_block:1;
+			} large_config;
+			struct {
+				u32 dst_module_id:16;
+				u32 dst_instance_id:8;
+				u32 dst_queue:3;
+				u32 src_queue:3;
+			} bind_unbind;
 		} ext;
 	};
 } __packed;
@@ -132,6 +159,13 @@ union avs_reply_msg {
 			struct {
 				u32 state:5;
 			} get_ppl_state;
+			/* module management */
+			struct {
+				u32 data_off_size:20;
+				u32 large_param_id:8;
+				u32 final_block:1;
+				u32 init_block:1;
+			} large_config;
 		} ext;
 	};
 } __packed;
@@ -237,4 +271,23 @@ int avs_ipc_set_pipeline_state(struct avs_dev *adev, u8 instance_id,
 int avs_ipc_get_pipeline_state(struct avs_dev *adev, u8 instance_id,
 			       enum avs_pipeline_state *state);
 
+/* Module management messages */
+int avs_ipc_init_instance(struct avs_dev *adev, u16 module_id, u8 instance_id,
+			  u8 ppl_id, u8 core_id, u8 domain,
+			  void *param, u32 param_size);
+int avs_ipc_delete_instance(struct avs_dev *adev, u16 module_id,
+			    u8 instance_id);
+int avs_ipc_bind(struct avs_dev *adev, u16 module_id, u8 instance_id,
+		 u16 dst_module_id, u8 dst_instance_id,
+		 u8 dst_queue, u8 src_queue);
+int avs_ipc_unbind(struct avs_dev *adev, u16 module_id, u8 instance_id,
+		   u16 dst_module_id, u8 dst_instance_id,
+		   u8 dst_queue, u8 src_queue);
+int avs_ipc_set_large_config(struct avs_dev *adev, u16 module_id,
+			     u8 instance_id, u8 param_id,
+			     u8 *request, size_t request_size);
+int avs_ipc_get_large_config(struct avs_dev *adev, u16 module_id, u8 instance_id,
+			     u8 param_id, u8 *request_data, size_t request_size,
+			     u8 **reply_data, size_t *reply_size);
+
 #endif /* __SOUND_SOC_INTEL_AVS_MSGS_H */
-- 
2.25.1


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

* [PATCH v3 08/17] ASoC: Intel: avs: Add power management requests
  2022-03-04 14:57 [PATCH v3 00/17] ASoC: Intel: AVS - Audio DSP for cAVS Cezary Rojewski
                   ` (6 preceding siblings ...)
  2022-03-04 14:57 ` [PATCH v3 07/17] ASoC: Intel: avs: Add module " Cezary Rojewski
@ 2022-03-04 14:57 ` Cezary Rojewski
  2022-03-04 16:24   ` Ranjani Sridharan
  2022-03-04 14:57 ` [PATCH v3 09/17] ASoC: Intel: avs: Add ROM requests Cezary Rojewski
                   ` (8 subsequent siblings)
  16 siblings, 1 reply; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-04 14:57 UTC (permalink / raw)
  To: alsa-devel
  Cc: Cezary Rojewski, rad, upstream, harshapriya.n, tiwai,
	pierre-louis.bossart, hdegoede, broonie, amadeuszx.slawinski,
	cujomalainey, lma

Audio DSP supports low power states i.e.: transitions between D0 and D3
and D0-substates in form of D0i0 and D0i3. That process is a combination
of core and IPC operations. Here, Dx and D0ix IPC handlers are added.

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/messages.c | 44 ++++++++++++++++++++++++++++++++++
 sound/soc/intel/avs/messages.h | 15 ++++++++++++
 2 files changed, 59 insertions(+)

diff --git a/sound/soc/intel/avs/messages.c b/sound/soc/intel/avs/messages.c
index 613c9452226d..e8f441b28d71 100644
--- a/sound/soc/intel/avs/messages.c
+++ b/sound/soc/intel/avs/messages.c
@@ -401,3 +401,47 @@ int avs_ipc_get_large_config(struct avs_dev *adev, u16 module_id, u8 instance_id
 
 	return 0;
 }
+
+int avs_ipc_set_dx(struct avs_dev *adev, u32 core_mask, bool powerup)
+{
+	union avs_module_msg msg = AVS_MODULE_REQUEST(SET_DX);
+	struct avs_ipc_msg request;
+	struct avs_dxstate_info dx;
+	int ret;
+
+	dx.core_mask = core_mask;
+	dx.dx_mask = powerup ? core_mask : 0;
+	request.header = msg.val;
+	request.data = &dx;
+	request.size = sizeof(dx);
+
+	ret = avs_dsp_send_msg(adev, &request, NULL);
+	if (ret)
+		avs_ipc_err(adev, &request, "set dx", ret);
+
+	return ret;
+}
+
+/*
+ * avs_ipc_set_d0ix - Set power gating policy (entering D0IX substates)
+ *
+ * @enable_pg: Whether to enable or disable power gating
+ * @streaming: Whether a stream is running when transitioning
+ */
+int avs_ipc_set_d0ix(struct avs_dev *adev, bool enable_pg, bool streaming)
+{
+	union avs_module_msg msg = AVS_MODULE_REQUEST(SET_D0IX);
+	struct avs_ipc_msg request = {{0}};
+	int ret;
+
+	msg.ext.set_d0ix.wake = enable_pg;
+	msg.ext.set_d0ix.streaming = streaming;
+
+	request.header = msg.val;
+
+	ret = avs_dsp_send_msg(adev, &request, NULL);
+	if (ret)
+		avs_ipc_err(adev, &request, "set d0ix", ret);
+
+	return ret;
+}
diff --git a/sound/soc/intel/avs/messages.h b/sound/soc/intel/avs/messages.h
index e4b95b066d70..69920f5e802b 100644
--- a/sound/soc/intel/avs/messages.h
+++ b/sound/soc/intel/avs/messages.h
@@ -97,6 +97,8 @@ enum avs_module_msg_type {
 	AVS_MOD_LARGE_CONFIG_SET = 4,
 	AVS_MOD_BIND = 5,
 	AVS_MOD_UNBIND = 6,
+	AVS_MOD_SET_DX = 7,
+	AVS_MOD_SET_D0IX = 8,
 	AVS_MOD_DELETE_INSTANCE = 11,
 };
 
@@ -133,6 +135,10 @@ union avs_module_msg {
 				u32 dst_queue:3;
 				u32 src_queue:3;
 			} bind_unbind;
+			struct {
+				u32 wake:1;
+				u32 streaming:1;
+			} set_d0ix;
 		} ext;
 	};
 } __packed;
@@ -290,4 +296,13 @@ int avs_ipc_get_large_config(struct avs_dev *adev, u16 module_id, u8 instance_id
 			     u8 param_id, u8 *request_data, size_t request_size,
 			     u8 **reply_data, size_t *reply_size);
 
+/* DSP cores and domains power management messages */
+struct avs_dxstate_info {
+	u32 core_mask;	/* which cores are subject for power transition */
+	u32 dx_mask;	/* bit[n]=1 core n goes to D0, bit[n]=0 it goes to D3 */
+} __packed;
+
+int avs_ipc_set_dx(struct avs_dev *adev, u32 core_mask, bool powerup);
+int avs_ipc_set_d0ix(struct avs_dev *adev, bool enable_pg, bool streaming);
+
 #endif /* __SOUND_SOC_INTEL_AVS_MSGS_H */
-- 
2.25.1


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

* [PATCH v3 09/17] ASoC: Intel: avs: Add ROM requests
  2022-03-04 14:57 [PATCH v3 00/17] ASoC: Intel: AVS - Audio DSP for cAVS Cezary Rojewski
                   ` (7 preceding siblings ...)
  2022-03-04 14:57 ` [PATCH v3 08/17] ASoC: Intel: avs: Add power " Cezary Rojewski
@ 2022-03-04 14:57 ` Cezary Rojewski
  2022-03-04 16:26   ` Ranjani Sridharan
  2022-03-04 14:57 ` [PATCH v3 10/17] ASoC: Intel: avs: Add basefw runtime-parameter requests Cezary Rojewski
                   ` (7 subsequent siblings)
  16 siblings, 1 reply; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-04 14:57 UTC (permalink / raw)
  To: alsa-devel
  Cc: Cezary Rojewski, rad, upstream, harshapriya.n, tiwai,
	pierre-louis.bossart, hdegoede, broonie, amadeuszx.slawinski,
	cujomalainey, lma

ROM requests are messages initiated by Host to alter firmware early boot
process. They specify whether the next boot should be a fresh start or if
IMR can be used to speed things up.

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/messages.c | 18 ++++++++++++++++++
 sound/soc/intel/avs/messages.h | 14 ++++++++++++++
 2 files changed, 32 insertions(+)

diff --git a/sound/soc/intel/avs/messages.c b/sound/soc/intel/avs/messages.c
index e8f441b28d71..f7d00e541323 100644
--- a/sound/soc/intel/avs/messages.c
+++ b/sound/soc/intel/avs/messages.c
@@ -12,6 +12,24 @@
 
 #define AVS_CL_TIMEOUT_MS	5000
 
+int avs_ipc_set_boot_config(struct avs_dev *adev, u32 dma_id, u32 purge)
+{
+	union avs_global_msg msg = AVS_GLOBAL_REQUEST(ROM_CONTROL);
+	struct avs_ipc_msg request = {{0}};
+	int ret;
+
+	msg.boot_cfg.rom_ctrl_msg_type = AVS_ROM_SET_BOOT_CONFIG;
+	msg.boot_cfg.dma_id = dma_id;
+	msg.boot_cfg.purge_request = purge;
+	request.header = msg.val;
+
+	ret = avs_dsp_send_rom_msg(adev, &request);
+	if (ret)
+		avs_ipc_err(adev, &request, "set boot config", ret);
+
+	return ret;
+}
+
 int avs_ipc_load_modules(struct avs_dev *adev, u16 *mod_ids, u32 num_mod_ids)
 {
 	union avs_global_msg msg = AVS_GLOBAL_REQUEST(LOAD_MULTIPLE_MODULES);
diff --git a/sound/soc/intel/avs/messages.h b/sound/soc/intel/avs/messages.h
index 69920f5e802b..615a61cef4f6 100644
--- a/sound/soc/intel/avs/messages.h
+++ b/sound/soc/intel/avs/messages.h
@@ -24,6 +24,7 @@ enum avs_msg_direction {
 };
 
 enum avs_global_msg_type {
+	AVS_GLB_ROM_CONTROL = 1,
 	AVS_GLB_LOAD_MULTIPLE_MODULES = 15,
 	AVS_GLB_UNLOAD_MULTIPLE_MODULES = 16,
 	AVS_GLB_CREATE_PIPELINE = 17,
@@ -45,6 +46,12 @@ union avs_global_msg {
 				u32 msg_direction:1;
 				u32 msg_target:1;
 			};
+			/* set boot config */
+			struct {
+				u32 rom_ctrl_msg_type:9;
+				u32 dma_id:5;
+				u32 purge_request:1;
+			} boot_cfg;
 			/* module loading */
 			struct {
 				u32 mod_cnt:8;
@@ -255,6 +262,13 @@ struct avs_notify_mod_data {
 	u32 data[];
 } __packed;
 
+/* ROM messages */
+enum avs_rom_control_msg_type {
+	AVS_ROM_SET_BOOT_CONFIG = 0,
+};
+
+int avs_ipc_set_boot_config(struct avs_dev *adev, u32 dma_id, u32 purge);
+
 /* Code loading messages */
 int avs_ipc_load_modules(struct avs_dev *adev, u16 *mod_ids, u32 num_mod_ids);
 int avs_ipc_unload_modules(struct avs_dev *adev, u16 *mod_ids, u32 num_mod_ids);
-- 
2.25.1


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

* [PATCH v3 10/17] ASoC: Intel: avs: Add basefw runtime-parameter requests
  2022-03-04 14:57 [PATCH v3 00/17] ASoC: Intel: AVS - Audio DSP for cAVS Cezary Rojewski
                   ` (8 preceding siblings ...)
  2022-03-04 14:57 ` [PATCH v3 09/17] ASoC: Intel: avs: Add ROM requests Cezary Rojewski
@ 2022-03-04 14:57 ` Cezary Rojewski
  2022-03-04 16:31   ` Ranjani Sridharan
  2022-03-04 14:57 ` [PATCH v3 11/17] ASoC: Intel: avs: Firmware resources management utilities Cezary Rojewski
                   ` (6 subsequent siblings)
  16 siblings, 1 reply; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-04 14:57 UTC (permalink / raw)
  To: alsa-devel
  Cc: Cezary Rojewski, rad, upstream, harshapriya.n, tiwai,
	pierre-louis.bossart, hdegoede, broonie, amadeuszx.slawinski,
	cujomalainey, lma

Each module may expose a range of runtime parameters. For basefw,
implement handlers for: FIRMWARE_CONFIG, HARDWARE_CONFIG and
MODULES_INFO. These are used by driver to dynamically allocate resources
in respect to platform details, reducing number of hardcodes and code
duplications that would otherwise be needed to be defined within the
driver code.

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/messages.c | 215 +++++++++++++++++++++++++++++++++
 sound/soc/intel/avs/messages.h | 179 +++++++++++++++++++++++++++
 2 files changed, 394 insertions(+)

diff --git a/sound/soc/intel/avs/messages.c b/sound/soc/intel/avs/messages.c
index f7d00e541323..7a2a7206df4b 100644
--- a/sound/soc/intel/avs/messages.c
+++ b/sound/soc/intel/avs/messages.c
@@ -463,3 +463,218 @@ int avs_ipc_set_d0ix(struct avs_dev *adev, bool enable_pg, bool streaming)
 
 	return ret;
 }
+
+int avs_ipc_get_fw_config(struct avs_dev *adev, struct avs_fw_cfg *cfg)
+{
+	struct avs_tlv *tlv;
+	size_t payload_size;
+	size_t offset = 0;
+	u8 *payload;
+	int ret;
+
+	ret = avs_ipc_get_large_config(adev, AVS_BASEFW_MOD_ID, AVS_BASEFW_INST_ID,
+				       AVS_BASEFW_FIRMWARE_CONFIG, NULL, 0,
+				       &payload, &payload_size);
+	if (ret)
+		return ret;
+
+	while (offset < payload_size) {
+		tlv = (struct avs_tlv *)(payload + offset);
+
+		switch (tlv->type) {
+		case AVS_FW_CFG_FW_VERSION:
+			memcpy(&cfg->fw_version, tlv->value,
+				sizeof(cfg->fw_version));
+			break;
+
+		case AVS_FW_CFG_MEMORY_RECLAIMED:
+			cfg->memory_reclaimed = *tlv->value;
+			break;
+
+		case AVS_FW_CFG_SLOW_CLOCK_FREQ_HZ:
+			cfg->slow_clock_freq_hz = *tlv->value;
+			break;
+
+		case AVS_FW_CFG_FAST_CLOCK_FREQ_HZ:
+			cfg->fast_clock_freq_hz = *tlv->value;
+			break;
+
+		case AVS_FW_CFG_ALH_SUPPORT_LEVEL:
+			cfg->alh_support = *tlv->value;
+			break;
+
+		case AVS_FW_CFG_IPC_DL_MAILBOX_BYTES:
+			cfg->ipc_dl_mailbox_bytes = *tlv->value;
+			break;
+
+		case AVS_FW_CFG_IPC_UL_MAILBOX_BYTES:
+			cfg->ipc_ul_mailbox_bytes = *tlv->value;
+			break;
+
+		case AVS_FW_CFG_TRACE_LOG_BYTES:
+			cfg->trace_log_bytes = *tlv->value;
+			break;
+
+		case AVS_FW_CFG_MAX_PPL_COUNT:
+			cfg->max_ppl_count = *tlv->value;
+			break;
+
+		case AVS_FW_CFG_MAX_ASTATE_COUNT:
+			cfg->max_astate_count = *tlv->value;
+			break;
+
+		case AVS_FW_CFG_MAX_MODULE_PIN_COUNT:
+			cfg->max_module_pin_count = *tlv->value;
+			break;
+
+		case AVS_FW_CFG_MODULES_COUNT:
+			cfg->modules_count = *tlv->value;
+			break;
+
+		case AVS_FW_CFG_MAX_MOD_INST_COUNT:
+			cfg->max_mod_inst_count = *tlv->value;
+			break;
+
+		case AVS_FW_CFG_MAX_LL_TASKS_PER_PRI_COUNT:
+			cfg->max_ll_tasks_per_pri_count = *tlv->value;
+			break;
+
+		case AVS_FW_CFG_LL_PRI_COUNT:
+			cfg->ll_pri_count = *tlv->value;
+			break;
+
+		case AVS_FW_CFG_MAX_DP_TASKS_COUNT:
+			cfg->max_dp_tasks_count = *tlv->value;
+			break;
+
+		case AVS_FW_CFG_MAX_LIBS_COUNT:
+			cfg->max_libs_count = *tlv->value;
+			break;
+
+		case AVS_FW_CFG_XTAL_FREQ_HZ:
+			cfg->xtal_freq_hz = *tlv->value;
+			break;
+
+		case AVS_FW_CFG_POWER_GATING_POLICY:
+			cfg->power_gating_policy = *tlv->value;
+			break;
+
+		/* Known but not useful to us. */
+		case AVS_FW_CFG_DMA_BUFFER_CONFIG:
+		case AVS_FW_CFG_SCHEDULER_CONFIG:
+		case AVS_FW_CFG_CLOCKS_CONFIG:
+			break;
+
+		default:
+			dev_info(adev->dev, "Unrecognized fw param: %d\n",
+				 tlv->type);
+			break;
+		}
+
+		offset += sizeof(*tlv) + tlv->length;
+	}
+
+	kfree(payload);
+	return ret;
+}
+
+int avs_ipc_get_hw_config(struct avs_dev *adev, struct avs_hw_cfg *cfg)
+{
+	struct avs_tlv *tlv;
+	size_t payload_size;
+	size_t size, offset = 0;
+	u8 *payload;
+	int ret;
+
+	ret = avs_ipc_get_large_config(adev, AVS_BASEFW_MOD_ID, AVS_BASEFW_INST_ID,
+				       AVS_BASEFW_HARDWARE_CONFIG, NULL, 0,
+				       &payload, &payload_size);
+	if (ret)
+		return ret;
+
+	while (offset < payload_size) {
+		tlv = (struct avs_tlv *)(payload + offset);
+
+		switch (tlv->type) {
+		case AVS_HW_CFG_AVS_VER:
+			cfg->avs_version = *tlv->value;
+			break;
+
+		case AVS_HW_CFG_DSP_CORES:
+			cfg->dsp_cores = *tlv->value;
+			break;
+
+		case AVS_HW_CFG_MEM_PAGE_BYTES:
+			cfg->mem_page_bytes = *tlv->value;
+			break;
+
+		case AVS_HW_CFG_TOTAL_PHYS_MEM_PAGES:
+			cfg->total_phys_mem_pages = *tlv->value;
+			break;
+
+		case AVS_HW_CFG_I2S_CAPS:
+			cfg->i2s_caps.i2s_version = tlv->value[0];
+			size = tlv->value[1];
+			cfg->i2s_caps.ctrl_count = size;
+			if (!size)
+				break;
+
+			/* Multiply to get entire array size. */
+			size *= sizeof(*cfg->i2s_caps.ctrl_base_addr);
+			cfg->i2s_caps.ctrl_base_addr = devm_kmemdup(adev->dev,
+								    &tlv->value[2],
+								    size, GFP_KERNEL);
+			if (!cfg->i2s_caps.ctrl_base_addr) {
+				ret = -ENOMEM;
+				goto exit;
+			}
+			break;
+
+		case AVS_HW_CFG_GATEWAY_COUNT:
+			cfg->gateway_count = *tlv->value;
+			break;
+
+		case AVS_HW_CFG_HP_EBB_COUNT:
+			cfg->hp_ebb_count = *tlv->value;
+			break;
+
+		case AVS_HW_CFG_LP_EBB_COUNT:
+			cfg->lp_ebb_count = *tlv->value;
+			break;
+
+		case AVS_HW_CFG_EBB_SIZE_BYTES:
+			cfg->ebb_size_bytes = *tlv->value;
+			break;
+
+		case AVS_HW_CFG_GPDMA_CAPS:
+			break;
+
+		default:
+			dev_info(adev->dev, "Unrecognized hw config: %d\n",
+				 tlv->type);
+			break;
+		}
+
+		offset += sizeof(*tlv) + tlv->length;
+	}
+
+exit:
+	kfree(payload);
+	return ret;
+}
+
+int avs_ipc_get_modules_info(struct avs_dev *adev, struct avs_mods_info **info)
+{
+	size_t payload_size;
+	u8 *payload;
+	int ret;
+
+	ret = avs_ipc_get_large_config(adev, AVS_BASEFW_MOD_ID, AVS_BASEFW_INST_ID,
+				       AVS_BASEFW_MODULES_INFO, NULL, 0,
+				       &payload, &payload_size);
+	if (ret)
+		return ret;
+
+	*info = (struct avs_mods_info *)payload;
+	return 0;
+}
diff --git a/sound/soc/intel/avs/messages.h b/sound/soc/intel/avs/messages.h
index 615a61cef4f6..67ba0a6347a1 100644
--- a/sound/soc/intel/avs/messages.h
+++ b/sound/soc/intel/avs/messages.h
@@ -319,4 +319,183 @@ struct avs_dxstate_info {
 int avs_ipc_set_dx(struct avs_dev *adev, u32 core_mask, bool powerup);
 int avs_ipc_set_d0ix(struct avs_dev *adev, bool enable_pg, bool streaming);
 
+/* Base-firmware runtime parameters */
+
+#define AVS_BASEFW_MOD_ID	0
+#define AVS_BASEFW_INST_ID	0
+
+enum avs_basefw_runtime_param {
+	AVS_BASEFW_FIRMWARE_CONFIG = 7,
+	AVS_BASEFW_HARDWARE_CONFIG = 8,
+	AVS_BASEFW_MODULES_INFO = 9,
+	AVS_BASEFW_LIBRARIES_INFO = 16,
+};
+
+struct avs_fw_version {
+	u16 major;
+	u16 minor;
+	u16 hotfix;
+	u16 build;
+};
+
+enum avs_fw_cfg_params {
+	AVS_FW_CFG_FW_VERSION = 0,
+	AVS_FW_CFG_MEMORY_RECLAIMED,
+	AVS_FW_CFG_SLOW_CLOCK_FREQ_HZ,
+	AVS_FW_CFG_FAST_CLOCK_FREQ_HZ,
+	AVS_FW_CFG_DMA_BUFFER_CONFIG,
+	AVS_FW_CFG_ALH_SUPPORT_LEVEL,
+	AVS_FW_CFG_IPC_DL_MAILBOX_BYTES,
+	AVS_FW_CFG_IPC_UL_MAILBOX_BYTES,
+	AVS_FW_CFG_TRACE_LOG_BYTES,
+	AVS_FW_CFG_MAX_PPL_COUNT,
+	AVS_FW_CFG_MAX_ASTATE_COUNT,
+	AVS_FW_CFG_MAX_MODULE_PIN_COUNT,
+	AVS_FW_CFG_MODULES_COUNT,
+	AVS_FW_CFG_MAX_MOD_INST_COUNT,
+	AVS_FW_CFG_MAX_LL_TASKS_PER_PRI_COUNT,
+	AVS_FW_CFG_LL_PRI_COUNT,
+	AVS_FW_CFG_MAX_DP_TASKS_COUNT,
+	AVS_FW_CFG_MAX_LIBS_COUNT,
+	AVS_FW_CFG_SCHEDULER_CONFIG,
+	AVS_FW_CFG_XTAL_FREQ_HZ,
+	AVS_FW_CFG_CLOCKS_CONFIG,
+	AVS_FW_CFG_RESERVED,
+	AVS_FW_CFG_POWER_GATING_POLICY,
+	AVS_FW_CFG_ASSERT_MODE,
+};
+
+struct avs_fw_cfg {
+	struct avs_fw_version fw_version;
+	u32 memory_reclaimed;
+	u32 slow_clock_freq_hz;
+	u32 fast_clock_freq_hz;
+	u32 alh_support;
+	u32 ipc_dl_mailbox_bytes;
+	u32 ipc_ul_mailbox_bytes;
+	u32 trace_log_bytes;
+	u32 max_ppl_count;
+	u32 max_astate_count;
+	u32 max_module_pin_count;
+	u32 modules_count;
+	u32 max_mod_inst_count;
+	u32 max_ll_tasks_per_pri_count;
+	u32 ll_pri_count;
+	u32 max_dp_tasks_count;
+	u32 max_libs_count;
+	u32 xtal_freq_hz;
+	u32 power_gating_policy;
+};
+
+int avs_ipc_get_fw_config(struct avs_dev *adev, struct avs_fw_cfg *cfg);
+
+enum avs_hw_cfg_params {
+	AVS_HW_CFG_AVS_VER,
+	AVS_HW_CFG_DSP_CORES,
+	AVS_HW_CFG_MEM_PAGE_BYTES,
+	AVS_HW_CFG_TOTAL_PHYS_MEM_PAGES,
+	AVS_HW_CFG_I2S_CAPS,
+	AVS_HW_CFG_GPDMA_CAPS,
+	AVS_HW_CFG_GATEWAY_COUNT,
+	AVS_HW_CFG_HP_EBB_COUNT,
+	AVS_HW_CFG_LP_EBB_COUNT,
+	AVS_HW_CFG_EBB_SIZE_BYTES,
+};
+
+enum avs_iface_version {
+	AVS_AVS_VER_1_5 = 0x10005,
+	AVS_AVS_VER_1_8 = 0x10008,
+};
+
+enum avs_i2s_version {
+	AVS_I2S_VER_15_SKYLAKE   = 0x00000,
+	AVS_I2S_VER_15_BROXTON   = 0x10000,
+	AVS_I2S_VER_15_BROXTON_P = 0x20000,
+	AVS_I2S_VER_18_KBL_CNL   = 0x30000,
+};
+
+struct avs_i2s_caps {
+	u32 i2s_version;
+	u32 ctrl_count;
+	u32 *ctrl_base_addr;
+};
+
+struct avs_hw_cfg {
+	u32 avs_version;
+	u32 dsp_cores;
+	u32 mem_page_bytes;
+	u32 total_phys_mem_pages;
+	struct avs_i2s_caps i2s_caps;
+	u32 gateway_count;
+	u32 hp_ebb_count;
+	u32 lp_ebb_count;
+	u32 ebb_size_bytes;
+};
+
+int avs_ipc_get_hw_config(struct avs_dev *adev, struct avs_hw_cfg *cfg);
+
+#define AVS_MODULE_LOAD_TYPE_BUILTIN	0
+#define AVS_MODULE_LOAD_TYPE_LOADABLE	1
+#define AVS_MODULE_STATE_LOADED		BIT(0)
+
+struct avs_module_type {
+	u32 load_type:4;
+	u32 auto_start:1;
+	u32 domain_ll:1;
+	u32 domain_dp:1;
+	u32 lib_code:1;
+	u32 rsvd:24;
+} __packed;
+
+union avs_segment_flags {
+	u32 ul;
+	struct {
+		u32 contents:1;
+		u32 alloc:1;
+		u32 load:1;
+		u32 readonly:1;
+		u32 code:1;
+		u32 data:1;
+		u32 rsvd_1:2;
+		u32 type:4;
+		u32 rsvd_2:4;
+		u32 length:16;
+	};
+} __packed;
+
+struct avs_segment_desc {
+	union avs_segment_flags flags;
+	u32 v_base_addr;
+	u32 file_offset;
+} __packed;
+
+struct avs_module_entry {
+	u16 module_id;
+	u16 state_flags;
+	u8 name[8];
+	guid_t uuid;
+	struct avs_module_type type;
+	u8 hash[32];
+	u32 entry_point;
+	u16 cfg_offset;
+	u16 cfg_count;
+	u32 affinity_mask;
+	u16 instance_max_count;
+	u16 instance_bss_size;
+	struct avs_segment_desc segments[3];
+} __packed;
+
+struct avs_mods_info {
+	u32 count;
+	struct avs_module_entry entries[];
+} __packed;
+
+static inline bool avs_module_entry_is_loaded(struct avs_module_entry *mentry)
+{
+	return mentry->type.load_type == AVS_MODULE_LOAD_TYPE_BUILTIN ||
+	       mentry->state_flags & AVS_MODULE_STATE_LOADED;
+}
+
+int avs_ipc_get_modules_info(struct avs_dev *adev, struct avs_mods_info **info);
+
 #endif /* __SOUND_SOC_INTEL_AVS_MSGS_H */
-- 
2.25.1


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

* [PATCH v3 11/17] ASoC: Intel: avs: Firmware resources management utilities
  2022-03-04 14:57 [PATCH v3 00/17] ASoC: Intel: AVS - Audio DSP for cAVS Cezary Rojewski
                   ` (9 preceding siblings ...)
  2022-03-04 14:57 ` [PATCH v3 10/17] ASoC: Intel: avs: Add basefw runtime-parameter requests Cezary Rojewski
@ 2022-03-04 14:57 ` Cezary Rojewski
  2022-03-04 16:41   ` Ranjani Sridharan
  2022-03-04 14:57 ` [PATCH v3 12/17] ASoC: Intel: avs: Declare module configuration types Cezary Rojewski
                   ` (5 subsequent siblings)
  16 siblings, 1 reply; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-04 14:57 UTC (permalink / raw)
  To: alsa-devel
  Cc: Cezary Rojewski, rad, upstream, harshapriya.n, tiwai,
	pierre-louis.bossart, hdegoede, broonie, amadeuszx.slawinski,
	cujomalainey, lma

With basefw runtime parameter handlers added, implement utility
functions to ease pipelines and modules allocation. IDA is enlisted to
help with that.

As firmware is modular and multiple binaries can be loaded on-demand
depending on the streaming scenario, custom firmware caching mechanism
is added.

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    |  37 +++++
 sound/soc/intel/avs/utils.c  | 301 +++++++++++++++++++++++++++++++++++
 3 files changed, 339 insertions(+), 1 deletion(-)
 create mode 100644 sound/soc/intel/avs/utils.c

diff --git a/sound/soc/intel/avs/Makefile b/sound/soc/intel/avs/Makefile
index c0824f30fd3b..d9f92c5f5407 100644
--- a/sound/soc/intel/avs/Makefile
+++ b/sound/soc/intel/avs/Makefile
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
-snd-soc-avs-objs := dsp.o ipc.o messages.o
+snd-soc-avs-objs := dsp.o ipc.o messages.o utils.o
 
 obj-$(CONFIG_SND_SOC_INTEL_AVS) += snd-soc-avs.o
diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h
index 841b8541b101..02d7591d0eac 100644
--- a/sound/soc/intel/avs/avs.h
+++ b/sound/soc/intel/avs/avs.h
@@ -53,12 +53,26 @@ struct avs_spec {
 	const u32 rom_status;
 };
 
+struct avs_fw_entry {
+	char *name;
+	const struct firmware *fw;
+
+	struct list_head node;
+};
+
 /*
  * struct avs_dev - Intel HD-Audio driver data
  *
  * @dev: PCI device
  * @dsp_ba: DSP bar address
  * @spec: platform-specific descriptor
+ * @fw_cfg: Firmware configuration, obtained through FW_CONFIG message
+ * @hw_cfg: Hardware configuration, obtained through HW_CONFIG message
+ * @mods_info: Available module-types, obtained through MODULES_INFO message
+ * @mod_idas: Module instance ID pool, one per module-type
+ * @modres_mutex: For synchronizing any @mods_info updates
+ * @ppl_ida: Pipeline instance ID pool
+ * @fw_list: List of libraries loaded, including base firmware
  */
 struct avs_dev {
 	struct hda_bus base;
@@ -68,6 +82,14 @@ struct avs_dev {
 	const struct avs_spec *spec;
 	struct avs_ipc *ipc;
 
+	struct avs_fw_cfg fw_cfg;
+	struct avs_hw_cfg hw_cfg;
+	struct avs_mods_info *mods_info;
+	struct ida **mod_idas;
+	struct mutex modres_mutex;
+	struct ida ppl_ida;
+	struct list_head fw_list;
+
 	struct completion fw_ready;
 };
 
@@ -168,4 +190,19 @@ 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);
 
+/* Firmware resources management */
+
+int avs_get_module_entry(struct avs_dev *adev, const guid_t *uuid, struct avs_module_entry *entry);
+int avs_get_module_id_entry(struct avs_dev *adev, u32 module_id, struct avs_module_entry *entry);
+int avs_get_module_id(struct avs_dev *adev, const guid_t *uuid);
+bool avs_is_module_ida_empty(struct avs_dev *adev, u32 module_id);
+
+int avs_module_info_init(struct avs_dev *adev, bool purge);
+void avs_module_info_free(struct avs_dev *adev);
+int avs_module_id_alloc(struct avs_dev *adev, u16 module_id);
+void avs_module_id_free(struct avs_dev *adev, u16 module_id, u8 instance_id);
+int avs_request_firmware(struct avs_dev *adev, const struct firmware **fw_p, const char *name);
+void avs_release_last_firmware(struct avs_dev *adev);
+void avs_release_firmwares(struct avs_dev *adev);
+
 #endif /* __SOUND_SOC_INTEL_AVS_H */
diff --git a/sound/soc/intel/avs/utils.c b/sound/soc/intel/avs/utils.c
new file mode 100644
index 000000000000..580f3e43fa12
--- /dev/null
+++ b/sound/soc/intel/avs/utils.c
@@ -0,0 +1,301 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/firmware.h>
+#include <linux/slab.h>
+#include "avs.h"
+#include "messages.h"
+
+/* Caller responsible for holding adev->modres_mutex. */
+static int avs_module_entry_index(struct avs_dev *adev, const guid_t *uuid)
+{
+	int i;
+
+	for (i = 0; i < adev->mods_info->count; i++) {
+		struct avs_module_entry *module;
+
+		module = &adev->mods_info->entries[i];
+		if (guid_equal(&module->uuid, uuid))
+			return i;
+	}
+
+	return -ENOENT;
+}
+
+/* Caller responsible for holding adev->modres_mutex. */
+static int avs_module_id_entry_index(struct avs_dev *adev, u32 module_id)
+{
+	int i;
+
+	for (i = 0; i < adev->mods_info->count; i++) {
+		struct avs_module_entry *module;
+
+		module = &adev->mods_info->entries[i];
+		if (module->module_id == module_id)
+			return i;
+	}
+
+	return -ENOENT;
+}
+
+int avs_get_module_entry(struct avs_dev *adev, const guid_t *uuid, struct avs_module_entry *entry)
+{
+	int idx;
+
+	mutex_lock(&adev->modres_mutex);
+
+	idx = avs_module_entry_index(adev, uuid);
+	if (idx >= 0)
+		memcpy(entry, &adev->mods_info->entries[idx], sizeof(*entry));
+
+	mutex_unlock(&adev->modres_mutex);
+	return (idx < 0) ? idx : 0;
+}
+
+int avs_get_module_id_entry(struct avs_dev *adev, u32 module_id, struct avs_module_entry *entry)
+{
+	int idx;
+
+	mutex_lock(&adev->modres_mutex);
+
+	idx = avs_module_id_entry_index(adev, module_id);
+	if (idx >= 0)
+		memcpy(entry, &adev->mods_info->entries[idx], sizeof(*entry));
+
+	mutex_unlock(&adev->modres_mutex);
+	return (idx < 0) ? idx : 0;
+}
+
+int avs_get_module_id(struct avs_dev *adev, const guid_t *uuid)
+{
+	struct avs_module_entry module;
+	int ret;
+
+	ret = avs_get_module_entry(adev, uuid, &module);
+	return !ret ? module.module_id : -ENOENT;
+}
+
+bool avs_is_module_ida_empty(struct avs_dev *adev, u32 module_id)
+{
+	bool ret = false;
+	int idx;
+
+	mutex_lock(&adev->modres_mutex);
+
+	idx = avs_module_id_entry_index(adev, module_id);
+	if (idx >= 0)
+		ret = ida_is_empty(adev->mod_idas[idx]);
+
+	mutex_unlock(&adev->modres_mutex);
+	return ret;
+}
+
+/* Caller responsible for holding adev->modres_mutex. */
+static void avs_module_ida_destroy(struct avs_dev *adev)
+{
+	int i = adev->mods_info ? adev->mods_info->count : 0;
+
+	while (i--) {
+		ida_destroy(adev->mod_idas[i]);
+		kfree(adev->mod_idas[i]);
+	}
+	kfree(adev->mod_idas);
+}
+
+/* Caller responsible for holding adev->modres_mutex. */
+static int
+avs_module_ida_alloc(struct avs_dev *adev, struct avs_mods_info *newinfo, bool purge)
+{
+	struct avs_mods_info *oldinfo = adev->mods_info;
+	struct ida **ida_ptrs;
+	u32 tocopy_count = 0;
+	int i;
+
+	if (!purge && oldinfo) {
+		if (oldinfo->count >= newinfo->count)
+			dev_warn(adev->dev, "refreshing %d modules info with %d\n",
+				 oldinfo->count, newinfo->count);
+		tocopy_count = oldinfo->count;
+	}
+
+	ida_ptrs = kcalloc(newinfo->count, sizeof(*ida_ptrs), GFP_KERNEL);
+	if (!ida_ptrs)
+		return -ENOMEM;
+
+	if (tocopy_count)
+		memcpy(ida_ptrs, adev->mod_idas, tocopy_count * sizeof(*ida_ptrs));
+
+	for (i = tocopy_count; i < newinfo->count; i++) {
+		ida_ptrs[i] = kzalloc(sizeof(**ida_ptrs), GFP_KERNEL);
+		if (!ida_ptrs[i]) {
+			while (i--)
+				kfree(ida_ptrs[i]);
+
+			kfree(ida_ptrs);
+			return -ENOMEM;
+		}
+
+		ida_init(ida_ptrs[i]);
+	}
+
+	/* If old elements have been reused, don't wipe them. */
+	if (tocopy_count)
+		kfree(adev->mod_idas);
+	else
+		avs_module_ida_destroy(adev);
+
+	adev->mod_idas = ida_ptrs;
+	return 0;
+}
+
+int avs_module_info_init(struct avs_dev *adev, bool purge)
+{
+	struct avs_mods_info *info;
+	int ret;
+
+	ret = avs_ipc_get_modules_info(adev, &info);
+	if (ret)
+		return AVS_IPC_RET(ret);
+
+	mutex_lock(&adev->modres_mutex);
+
+	ret = avs_module_ida_alloc(adev, info, purge);
+	if (ret < 0) {
+		dev_err(adev->dev, "initialize module idas failed: %d\n", ret);
+		goto exit;
+	}
+
+	/* Refresh current information with newly received table. */
+	kfree(adev->mods_info);
+	adev->mods_info = info;
+
+exit:
+	mutex_unlock(&adev->modres_mutex);
+	return ret;
+}
+
+void avs_module_info_free(struct avs_dev *adev)
+{
+	mutex_lock(&adev->modres_mutex);
+
+	avs_module_ida_destroy(adev);
+	kfree(adev->mods_info);
+	adev->mods_info = NULL;
+
+	mutex_unlock(&adev->modres_mutex);
+}
+
+int avs_module_id_alloc(struct avs_dev *adev, u16 module_id)
+{
+	int ret, idx, max_id;
+
+	mutex_lock(&adev->modres_mutex);
+
+	idx = avs_module_id_entry_index(adev, module_id);
+	if (idx == -ENOENT) {
+		WARN(1, "invalid module id: %d", module_id);
+		ret = -EINVAL;
+		goto exit;
+	}
+	max_id = adev->mods_info->entries[idx].instance_max_count - 1;
+	ret = ida_alloc_max(adev->mod_idas[idx], max_id, GFP_KERNEL);
+exit:
+	mutex_unlock(&adev->modres_mutex);
+	return ret;
+}
+
+void avs_module_id_free(struct avs_dev *adev, u16 module_id, u8 instance_id)
+{
+	int idx;
+
+	mutex_lock(&adev->modres_mutex);
+
+	idx = avs_module_id_entry_index(adev, module_id);
+	if (idx == -ENOENT) {
+		WARN(1, "invalid module id: %d", module_id);
+		goto exit;
+	}
+
+	ida_free(adev->mod_idas[idx], instance_id);
+exit:
+	mutex_unlock(&adev->modres_mutex);
+}
+
+/*
+ * Once driver loads FW it should keep it in memory, so we are not affected
+ * by FW removal from filesystem or even worse by loading different FW at
+ * runtime suspend/resume.
+ */
+int avs_request_firmware(struct avs_dev *adev, const struct firmware **fw_p, const char *name)
+{
+	struct avs_fw_entry *entry;
+	int ret;
+
+	/* first check in list if it is not already loaded */
+	list_for_each_entry(entry, &adev->fw_list, node) {
+		if (!strcmp(name, entry->name)) {
+			*fw_p = entry->fw;
+			return 0;
+		}
+	}
+
+	/* FW is not loaded, let's load it now and add to the list */
+	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	if (!entry)
+		return -ENOMEM;
+
+	entry->name = kstrdup(name, GFP_KERNEL);
+	if (!entry->name) {
+		kfree(entry);
+		return -ENOMEM;
+	}
+
+	ret = request_firmware(&entry->fw, name, adev->dev);
+	if (ret < 0) {
+		kfree(entry->name);
+		kfree(entry);
+		return ret;
+	}
+
+	*fw_p = entry->fw;
+
+	list_add_tail(&entry->node, &adev->fw_list);
+
+	return 0;
+}
+
+/*
+ * Release single FW entry, used to handle errors in functions calling
+ * avs_request_firmware()
+ */
+void avs_release_last_firmware(struct avs_dev *adev)
+{
+	struct avs_fw_entry *entry;
+
+	entry = list_last_entry(&adev->fw_list, typeof(*entry), node);
+
+	list_del(&entry->node);
+	release_firmware(entry->fw);
+	kfree(entry->name);
+	kfree(entry);
+}
+
+/*
+ * Release all FW entries, used on driver removal
+ */
+void avs_release_firmwares(struct avs_dev *adev)
+{
+	struct avs_fw_entry *entry, *tmp;
+
+	list_for_each_entry_safe(entry, tmp, &adev->fw_list, node) {
+		list_del(&entry->node);
+		release_firmware(entry->fw);
+		kfree(entry->name);
+		kfree(entry);
+	}
+}
-- 
2.25.1


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

* [PATCH v3 12/17] ASoC: Intel: avs: Declare module configuration types
  2022-03-04 14:57 [PATCH v3 00/17] ASoC: Intel: AVS - Audio DSP for cAVS Cezary Rojewski
                   ` (10 preceding siblings ...)
  2022-03-04 14:57 ` [PATCH v3 11/17] ASoC: Intel: avs: Firmware resources management utilities Cezary Rojewski
@ 2022-03-04 14:57 ` Cezary Rojewski
  2022-03-04 16:43   ` Ranjani Sridharan
  2022-03-04 14:57 ` [PATCH v3 13/17] ASoC: Intel: avs: Dynamic firmware resources management Cezary Rojewski
                   ` (4 subsequent siblings)
  16 siblings, 1 reply; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-04 14:57 UTC (permalink / raw)
  To: alsa-devel
  Cc: Cezary Rojewski, rad, upstream, harshapriya.n, tiwai,
	pierre-louis.bossart, hdegoede, broonie, amadeuszx.slawinski,
	cujomalainey, lma

Declare structures and constants for all modules being part of basefw
binary. These are used in streaming operations to communicate the needs
of software to firmware side.

While adding module types, append handler for SET_SINK_FORMAT runtime
for COPIER module which allows for configuration of output pin other
than the default one (0).

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/messages.c |  17 +++
 sound/soc/intel/avs/messages.h | 252 +++++++++++++++++++++++++++++++++
 2 files changed, 269 insertions(+)

diff --git a/sound/soc/intel/avs/messages.c b/sound/soc/intel/avs/messages.c
index 7a2a7206df4b..44566705e56c 100644
--- a/sound/soc/intel/avs/messages.c
+++ b/sound/soc/intel/avs/messages.c
@@ -678,3 +678,20 @@ int avs_ipc_get_modules_info(struct avs_dev *adev, struct avs_mods_info **info)
 	*info = (struct avs_mods_info *)payload;
 	return 0;
 }
+
+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,
+				   const struct avs_audio_format *sink_fmt)
+{
+	struct avs_copier_sink_format cpr_fmt;
+
+	cpr_fmt.sink_id = sink_id;
+	/* Firmware expects driver to resend copier's input format. */
+	cpr_fmt.src_fmt = *src_fmt;
+	cpr_fmt.sink_fmt = *sink_fmt;
+
+	return avs_ipc_set_large_config(adev, module_id, instance_id,
+					AVS_COPIER_SET_SINK_FORMAT,
+					(u8 *)&cpr_fmt, sizeof(cpr_fmt));
+}
diff --git a/sound/soc/intel/avs/messages.h b/sound/soc/intel/avs/messages.h
index 67ba0a6347a1..966139e9663d 100644
--- a/sound/soc/intel/avs/messages.h
+++ b/sound/soc/intel/avs/messages.h
@@ -498,4 +498,256 @@ 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);
 
+/* Module configuration */
+
+#define AVS_MIXIN_MOD_UUID \
+	GUID_INIT(0x39656EB2, 0x3B71, 0x4049, 0x8D, 0x3F, 0xF9, 0x2C, 0xD5, 0xC4, 0x3C, 0x09)
+
+#define AVS_MIXOUT_MOD_UUID \
+	GUID_INIT(0x3C56505A, 0x24D7, 0x418F, 0xBD, 0xDC, 0xC1, 0xF5, 0xA3, 0xAC, 0x2A, 0xE0)
+
+#define AVS_COPIER_MOD_UUID \
+	GUID_INIT(0x9BA00C83, 0xCA12, 0x4A83, 0x94, 0x3C, 0x1F, 0xA2, 0xE8, 0x2F, 0x9D, 0xDA)
+
+#define AVS_KPBUFF_MOD_UUID \
+	GUID_INIT(0xA8A0CB32, 0x4A77, 0x4DB1, 0x85, 0xC7, 0x53, 0xD7, 0xEE, 0x07, 0xBC, 0xE6)
+
+#define AVS_MICSEL_MOD_UUID \
+	GUID_INIT(0x32FE92C1, 0x1E17, 0x4FC2, 0x97, 0x58, 0xC7, 0xF3, 0x54, 0x2E, 0x98, 0x0A)
+
+#define AVS_MUX_MOD_UUID \
+	GUID_INIT(0x64CE6E35, 0x857A, 0x4878, 0xAC, 0xE8, 0xE2, 0xA2, 0xF4, 0x2e, 0x30, 0x69)
+
+#define AVS_UPDWMIX_MOD_UUID \
+	GUID_INIT(0x42F8060C, 0x832F, 0x4DBF, 0xB2, 0x47, 0x51, 0xE9, 0x61, 0x99, 0x7b, 0x35)
+
+#define AVS_SRCINTC_MOD_UUID \
+	GUID_INIT(0xE61BB28D, 0x149A, 0x4C1F, 0xB7, 0x09, 0x46, 0x82, 0x3E, 0xF5, 0xF5, 0xAE)
+
+#define AVS_PROBE_MOD_UUID \
+	GUID_INIT(0x7CAD0808, 0xAB10, 0xCD23, 0xEF, 0x45, 0x12, 0xAB, 0x34, 0xCD, 0x56, 0xEF)
+
+#define AVS_AEC_MOD_UUID \
+	GUID_INIT(0x46CB87FB, 0xD2C9, 0x4970, 0x96, 0xD2, 0x6D, 0x7E, 0x61, 0x4B, 0xB6, 0x05)
+
+#define AVS_ASRC_MOD_UUID \
+	GUID_INIT(0x66B4402D, 0xB468, 0x42F2, 0x81, 0xA7, 0xB3, 0x71, 0x21, 0x86, 0x3D, 0xD4)
+
+#define AVS_INTELWOV_MOD_UUID \
+	GUID_INIT(0xEC774FA9, 0x28D3, 0x424A, 0x90, 0xE4, 0x69, 0xF9, 0x84, 0xF1, 0xEE, 0xB7)
+
+/* channel map */
+enum avs_channel_index {
+	AVS_CHANNEL_LEFT = 0,
+	AVS_CHANNEL_RIGHT = 1,
+	AVS_CHANNEL_CENTER = 2,
+	AVS_CHANNEL_LEFT_SURROUND = 3,
+	AVS_CHANNEL_CENTER_SURROUND = 3,
+	AVS_CHANNEL_RIGHT_SURROUND = 4,
+	AVS_CHANNEL_LFE = 7,
+	AVS_CHANNEL_INVALID = 0xF,
+};
+
+enum avs_channel_config {
+	AVS_CHANNEL_CONFIG_MONO = 0,
+	AVS_CHANNEL_CONFIG_STEREO = 1,
+	AVS_CHANNEL_CONFIG_2_1 = 2,
+	AVS_CHANNEL_CONFIG_3_0 = 3,
+	AVS_CHANNEL_CONFIG_3_1 = 4,
+	AVS_CHANNEL_CONFIG_QUATRO = 5,
+	AVS_CHANNEL_CONFIG_4_0 = 6,
+	AVS_CHANNEL_CONFIG_5_0 = 7,
+	AVS_CHANNEL_CONFIG_5_1 = 8,
+	AVS_CHANNEL_CONFIG_DUAL_MONO = 9,
+	AVS_CHANNEL_CONFIG_I2S_DUAL_STEREO_0 = 10,
+	AVS_CHANNEL_CONFIG_I2S_DUAL_STEREO_1 = 11,
+	AVS_CHANNEL_CONFIG_4_CHANNEL = 12,
+	AVS_CHANNEL_CONFIG_INVALID
+};
+
+enum avs_interleaving {
+	AVS_INTERLEAVING_PER_CHANNEL = 0,
+	AVS_INTERLEAVING_PER_SAMPLE = 1,
+};
+
+enum avs_sample_type {
+	AVS_SAMPLE_TYPE_INT_MSB = 0,
+	AVS_SAMPLE_TYPE_INT_LSB = 1,
+	AVS_SAMPLE_TYPE_INT_SIGNED = 2,
+	AVS_SAMPLE_TYPE_INT_UNSIGNED = 3,
+	AVS_SAMPLE_TYPE_FLOAT = 4,
+};
+
+#define AVS_CHANNELS_MAX	8
+#define AVS_ALL_CHANNELS_MASK	UINT_MAX
+
+struct avs_audio_format {
+	u32 sampling_freq;
+	u32 bit_depth;
+	u32 channel_map;
+	u32 channel_config;
+	u32 interleaving;
+	u32 num_channels:8;
+	u32 valid_bit_depth:8;
+	u32 sample_type:8;
+	u32 reserved:8;
+} __packed;
+
+struct avs_modcfg_base {
+	u32 cpc;
+	u32 ibs;
+	u32 obs;
+	u32 is_pages;
+	struct avs_audio_format audio_fmt;
+} __packed;
+
+struct avs_pin_format {
+	u32 pin_index;
+	u32 iobs;
+	struct avs_audio_format audio_fmt;
+} __packed;
+
+struct avs_modcfg_ext {
+	struct avs_modcfg_base base;
+	u16 num_input_pins;
+	u16 num_output_pins;
+	u8 reserved[12];
+	/* input pin formats followed by output ones */
+	struct avs_pin_format pin_fmts[];
+} __packed;
+
+enum avs_dma_type {
+	AVS_DMA_HDA_HOST_OUTPUT = 0,
+	AVS_DMA_HDA_HOST_INPUT = 1,
+	AVS_DMA_HDA_LINK_OUTPUT = 8,
+	AVS_DMA_HDA_LINK_INPUT = 9,
+	AVS_DMA_DMIC_LINK_INPUT = 11,
+	AVS_DMA_I2S_LINK_OUTPUT = 12,
+	AVS_DMA_I2S_LINK_INPUT = 13,
+};
+
+union avs_virtual_index {
+	u8 val;
+	struct {
+		u8 time_slot:4;
+		u8 instance:4;
+	} i2s;
+	struct {
+		u8 queue_id:3;
+		u8 time_slot:2;
+		u8 instance:3;
+	} dmic;
+} __packed;
+
+union avs_connector_node_id {
+	u32 val;
+	struct {
+		u32 vindex:8;
+		u32 dma_type:5;
+		u32 rsvd:19;
+	};
+} __packed;
+
+#define INVALID_PIPELINE_ID	0xFF
+#define INVALID_NODE_ID \
+	((union avs_connector_node_id) { UINT_MAX })
+
+union avs_gtw_attributes {
+	u32 val;
+	struct {
+		u32 lp_buffer_alloc:1;
+		u32 rsvd:31;
+	};
+} __packed;
+
+struct avs_copier_gtw_cfg {
+	union avs_connector_node_id node_id;
+	u32 dma_buffer_size;
+	u32 config_length;
+	struct {
+		union avs_gtw_attributes attrs;
+		u32 blob[];
+	} config;
+} __packed;
+
+struct avs_copier_cfg {
+	struct avs_modcfg_base base;
+	struct avs_audio_format out_fmt;
+	u32 feature_mask;
+	struct avs_copier_gtw_cfg gtw_cfg;
+} __packed;
+
+struct avs_micsel_cfg {
+	struct avs_modcfg_base base;
+	struct avs_audio_format out_fmt;
+} __packed;
+
+struct avs_mux_cfg {
+	struct avs_modcfg_base base;
+	struct avs_audio_format ref_fmt;
+	struct avs_audio_format out_fmt;
+} __packed;
+
+struct avs_updown_mixer_cfg {
+	struct avs_modcfg_base base;
+	u32 out_channel_config;
+	u32 coefficients_select;
+	s32 coefficients[AVS_CHANNELS_MAX];
+	u32 channel_map;
+} __packed;
+
+struct avs_src_cfg {
+	struct avs_modcfg_base base;
+	u32 out_freq;
+} __packed;
+
+struct avs_probe_gtw_cfg {
+	union avs_connector_node_id node_id;
+	u32 dma_buffer_size;
+} __packed;
+
+struct avs_probe_cfg {
+	struct avs_modcfg_base base;
+	struct avs_probe_gtw_cfg gtw_cfg;
+} __packed;
+
+struct avs_aec_cfg {
+	struct avs_modcfg_base base;
+	struct avs_audio_format ref_fmt;
+	struct avs_audio_format out_fmt;
+	u32 cpc_lp_mode;
+} __packed;
+
+struct avs_asrc_cfg {
+	struct avs_modcfg_base base;
+	u32 out_freq;
+	u32 rsvd0:1;
+	u32 mode:1;
+	u32 rsvd2:2;
+	u32 disable_jitter_buffer:1;
+	u32 rsvd3:27;
+} __packed;
+
+struct avs_wov_cfg {
+	struct avs_modcfg_base base;
+	u32 cpc_lp_mode;
+} __packed;
+
+/* Module runtime parameters */
+
+enum avs_copier_runtime_param {
+	AVS_COPIER_SET_SINK_FORMAT = 2,
+};
+
+struct avs_copier_sink_format {
+	u32 sink_id;
+	struct avs_audio_format src_fmt;
+	struct avs_audio_format sink_fmt;
+} __packed;
+
+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,
+				   const struct avs_audio_format *sink_fmt);
+
 #endif /* __SOUND_SOC_INTEL_AVS_MSGS_H */
-- 
2.25.1


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

* [PATCH v3 13/17] ASoC: Intel: avs: Dynamic firmware resources management
  2022-03-04 14:57 [PATCH v3 00/17] ASoC: Intel: AVS - Audio DSP for cAVS Cezary Rojewski
                   ` (11 preceding siblings ...)
  2022-03-04 14:57 ` [PATCH v3 12/17] ASoC: Intel: avs: Declare module configuration types Cezary Rojewski
@ 2022-03-04 14:57 ` Cezary Rojewski
  2022-03-04 16:47   ` Ranjani Sridharan
  2022-03-04 14:57 ` [PATCH v3 14/17] ASoC: Intel: avs: General code loading flow Cezary Rojewski
                   ` (3 subsequent siblings)
  16 siblings, 1 reply; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-04 14:57 UTC (permalink / raw)
  To: alsa-devel
  Cc: Cezary Rojewski, rad, upstream, harshapriya.n, tiwai,
	pierre-louis.bossart, hdegoede, broonie, amadeuszx.slawinski,
	cujomalainey, lma

Wrap elementary DSP-core operations and resource control into more
complex handlers. This is done to reduce the number of invocations of
wrapped operations throughout the driver as order of operations matters -
most flows involve register manipulation and IPCs combined.

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 |  10 +++
 sound/soc/intel/avs/dsp.c | 170 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 180 insertions(+)

diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h
index 02d7591d0eac..0034c075fa64 100644
--- a/sound/soc/intel/avs/avs.h
+++ b/sound/soc/intel/avs/avs.h
@@ -89,6 +89,7 @@ struct avs_dev {
 	struct mutex modres_mutex;
 	struct ida ppl_ida;
 	struct list_head fw_list;
+	int *core_refs;
 
 	struct completion fw_ready;
 };
@@ -205,4 +206,13 @@ int avs_request_firmware(struct avs_dev *adev, const struct firmware **fw_p, con
 void avs_release_last_firmware(struct avs_dev *adev);
 void avs_release_firmwares(struct avs_dev *adev);
 
+int avs_dsp_init_module(struct avs_dev *adev, u16 module_id, u8 ppl_instance_id,
+			u8 core_id, u8 domain, void *param, u32 param_size,
+			u16 *instance_id);
+void avs_dsp_delete_module(struct avs_dev *adev, u16 module_id, u16 instance_id,
+			   u8 ppl_instance_id, u8 core_id);
+int avs_dsp_create_pipeline(struct avs_dev *adev, u16 req_size, u8 priority,
+			    bool lp, u16 attributes, u8 *instance_id);
+int avs_dsp_delete_pipeline(struct avs_dev *adev, u8 instance_id);
+
 #endif /* __SOUND_SOC_INTEL_AVS_H */
diff --git a/sound/soc/intel/avs/dsp.c b/sound/soc/intel/avs/dsp.c
index eb9d941fe6cf..5994d64d2468 100644
--- a/sound/soc/intel/avs/dsp.c
+++ b/sound/soc/intel/avs/dsp.c
@@ -104,4 +104,174 @@ int avs_dsp_core_disable(struct avs_dev *adev, u32 core_mask)
 	return avs_dsp_op(adev, power, core_mask, false);
 }
 
+static int avs_dsp_enable(struct avs_dev *adev, u32 core_mask)
+{
+	u32 mask;
+	int ret;
+
+	ret = avs_dsp_core_enable(adev, core_mask);
+	if (ret < 0)
+		return ret;
+
+	mask = core_mask & ~AVS_MAIN_CORE_MASK;
+	if (!mask)
+		/*
+		 * without main core, fw is dead anyway
+		 * so setting D0 for it is futile.
+		 */
+		return 0;
+
+	ret = avs_ipc_set_dx(adev, mask, true);
+	return AVS_IPC_RET(ret);
+}
+
+static int avs_dsp_disable(struct avs_dev *adev, u32 core_mask)
+{
+	int ret;
+
+	ret = avs_ipc_set_dx(adev, core_mask, false);
+	if (ret)
+		return AVS_IPC_RET(ret);
+
+	return avs_dsp_core_disable(adev, core_mask);
+}
+
+static int avs_dsp_get_core(struct avs_dev *adev, u32 core_id)
+{
+	u32 mask;
+	int ret;
+
+	mask = BIT_MASK(core_id);
+	if (mask == AVS_MAIN_CORE_MASK)
+		/* nothing to do for main core */
+		return 0;
+	if (core_id >= adev->hw_cfg.dsp_cores) {
+		ret = -EINVAL;
+		goto err;
+	}
+
+	adev->core_refs[core_id]++;
+	if (adev->core_refs[core_id] == 1) {
+		ret = avs_dsp_enable(adev, mask);
+		if (ret)
+			goto err_enable_dsp;
+	}
+
+	return 0;
+
+err_enable_dsp:
+	adev->core_refs[core_id]--;
+err:
+	dev_err(adev->dev, "get core %d failed: %d\n", core_id, ret);
+	return ret;
+}
+
+static int avs_dsp_put_core(struct avs_dev *adev, u32 core_id)
+{
+	u32 mask;
+	int ret;
+
+	mask = BIT_MASK(core_id);
+	if (mask == AVS_MAIN_CORE_MASK)
+		/* nothing to do for main core */
+		return 0;
+	if (core_id >= adev->hw_cfg.dsp_cores) {
+		ret = -EINVAL;
+		goto err;
+	}
+
+	adev->core_refs[core_id]--;
+	if (!adev->core_refs[core_id]) {
+		ret = avs_dsp_disable(adev, mask);
+		if (ret)
+			goto err;
+	}
+
+	return 0;
+err:
+	dev_err(adev->dev, "put core %d failed: %d\n", core_id, ret);
+	return ret;
+}
+
+int avs_dsp_init_module(struct avs_dev *adev, u16 module_id, u8 ppl_instance_id,
+			u8 core_id, u8 domain, void *param, u32 param_size,
+			u16 *instance_id)
+{
+	struct avs_module_entry mentry;
+	int ret, id;
+
+	id = avs_module_id_alloc(adev, module_id);
+	if (id < 0)
+		return id;
+
+	ret = avs_get_module_id_entry(adev, module_id, &mentry);
+	if (ret)
+		goto err_mod_entry;
+
+	ret = avs_dsp_get_core(adev, core_id);
+	if (ret)
+		goto err_mod_entry;
+
+	ret = avs_ipc_init_instance(adev, module_id, id, ppl_instance_id,
+				    core_id, domain, param, param_size);
+	if (ret) {
+		ret = AVS_IPC_RET(ret);
+		goto err_ipc;
+	}
+
+	*instance_id = id;
+	return 0;
+
+err_ipc:
+	avs_dsp_put_core(adev, core_id);
+err_mod_entry:
+	avs_module_id_free(adev, module_id, id);
+	return ret;
+}
+
+void avs_dsp_delete_module(struct avs_dev *adev, u16 module_id, u16 instance_id,
+			   u8 ppl_instance_id, u8 core_id)
+{
+	/* Modules not owned by any pipeline need to be freed explicitly. */
+	if (ppl_instance_id == INVALID_PIPELINE_ID)
+		avs_ipc_delete_instance(adev, module_id, instance_id);
+
+	avs_module_id_free(adev, module_id, instance_id);
+
+	avs_dsp_put_core(adev, core_id);
+}
+
+int avs_dsp_create_pipeline(struct avs_dev *adev, u16 req_size, u8 priority,
+			    bool lp, u16 attributes, u8 *instance_id)
+{
+	struct avs_fw_cfg *fw_cfg = &adev->fw_cfg;
+	int ret, id;
+
+	id = ida_alloc_max(&adev->ppl_ida, fw_cfg->max_ppl_count - 1, GFP_KERNEL);
+	if (id < 0)
+		return id;
+
+	ret = avs_ipc_create_pipeline(adev, req_size, priority, id, lp,
+				      attributes);
+	if (ret) {
+		ida_free(&adev->ppl_ida, id);
+		return AVS_IPC_RET(ret);
+	}
+
+	*instance_id = id;
+	return 0;
+}
+
+int avs_dsp_delete_pipeline(struct avs_dev *adev, u8 instance_id)
+{
+	int ret;
+
+	ret = avs_ipc_delete_pipeline(adev, instance_id);
+	if (ret)
+		ret = AVS_IPC_RET(ret);
+
+	ida_free(&adev->ppl_ida, instance_id);
+	return ret;
+}
+
 MODULE_LICENSE("GPL");
-- 
2.25.1


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

* [PATCH v3 14/17] ASoC: Intel: avs: General code loading flow
  2022-03-04 14:57 [PATCH v3 00/17] ASoC: Intel: AVS - Audio DSP for cAVS Cezary Rojewski
                   ` (12 preceding siblings ...)
  2022-03-04 14:57 ` [PATCH v3 13/17] ASoC: Intel: avs: Dynamic firmware resources management Cezary Rojewski
@ 2022-03-04 14:57 ` Cezary Rojewski
  2022-03-04 16:54   ` Ranjani Sridharan
  2022-03-04 14:57 ` [PATCH v3 15/17] ASoC: Intel: avs: Implement CLDMA transfer Cezary Rojewski
                   ` (2 subsequent siblings)
  16 siblings, 1 reply; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-04 14:57 UTC (permalink / raw)
  To: alsa-devel
  Cc: Cezary Rojewski, rad, upstream, harshapriya.n, tiwai,
	pierre-louis.bossart, hdegoede, broonie, amadeuszx.slawinski,
	cujomalainey, lma

Code loading is a complex procedure and requires combined effort of DMA
and IPCs. With IPCs already in place, lay out ground for specific DMA
transfer operations.

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       |  18 +++
 sound/soc/intel/avs/core.c      |  62 +++++++++
 sound/soc/intel/avs/dsp.c       |  26 ++++
 sound/soc/intel/avs/loader.c    | 237 ++++++++++++++++++++++++++++++++
 sound/soc/intel/avs/registers.h |   6 +
 6 files changed, 350 insertions(+), 1 deletion(-)
 create mode 100644 sound/soc/intel/avs/core.c
 create mode 100644 sound/soc/intel/avs/loader.c

diff --git a/sound/soc/intel/avs/Makefile b/sound/soc/intel/avs/Makefile
index d9f92c5f5407..d9c793160612 100644
--- a/sound/soc/intel/avs/Makefile
+++ b/sound/soc/intel/avs/Makefile
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
-snd-soc-avs-objs := dsp.o ipc.o messages.o utils.o
+snd-soc-avs-objs := dsp.o ipc.o messages.o utils.o core.o loader.o
 
 obj-$(CONFIG_SND_SOC_INTEL_AVS) += snd-soc-avs.o
diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h
index 0034c075fa64..2527d6170417 100644
--- a/sound/soc/intel/avs/avs.h
+++ b/sound/soc/intel/avs/avs.h
@@ -10,8 +10,11 @@
 #define __SOUND_SOC_INTEL_AVS_H
 
 #include <linux/device.h>
+#include <linux/firmware.h>
 #include <sound/hda_codec.h>
+#include <sound/hda_register.h>
 #include "messages.h"
+#include "registers.h"
 
 struct avs_dev;
 
@@ -32,6 +35,10 @@ struct avs_dsp_ops {
 	irqreturn_t (* const irq_handler)(int, void *);
 	irqreturn_t (* const irq_thread)(int, void *);
 	void (* const int_control)(struct avs_dev *, bool);
+	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);
 };
 
 #define avs_dsp_op(adev, op, ...) \
@@ -45,6 +52,7 @@ struct avs_spec {
 	const char *name;
 
 	const struct avs_dsp_ops *const dsp_ops;
+	struct avs_fw_version min_fw_version; /* anything below is rejected */
 
 	const u32 core_init_mask;	/* used during DSP boot */
 	const u64 attributes;		/* bitmask of AVS_PLATATTR_* */
@@ -90,6 +98,7 @@ struct avs_dev {
 	struct ida ppl_ida;
 	struct list_head fw_list;
 	int *core_refs;
+	char **lib_names;
 
 	struct completion fw_ready;
 };
@@ -215,4 +224,13 @@ int avs_dsp_create_pipeline(struct avs_dev *adev, u16 req_size, u8 priority,
 			    bool lp, u16 attributes, u8 *instance_id);
 int avs_dsp_delete_pipeline(struct avs_dev *adev, u8 instance_id);
 
+/* Firmware loading */
+
+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_boot_firmware(struct avs_dev *adev, bool purge);
+int avs_dsp_first_boot_firmware(struct avs_dev *adev);
+
 #endif /* __SOUND_SOC_INTEL_AVS_H */
diff --git a/sound/soc/intel/avs/core.c b/sound/soc/intel/avs/core.c
new file mode 100644
index 000000000000..117b31ef9cd0
--- /dev/null
+++ b/sound/soc/intel/avs/core.c
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+// Special thanks to:
+//    Krzysztof Hejmowski <krzysztof.hejmowski@intel.com>
+//    Michal Sienkiewicz <michal.sienkiewicz@intel.com>
+//    Filip Proborszcz
+//
+// for sharing Intel AudioDSP expertise and helping shape the very
+// foundation of this driver
+//
+
+#include <linux/pci.h>
+#include <sound/hdaudio.h>
+#include "avs.h"
+
+static void
+avs_hda_update_config_dword(struct hdac_bus *bus, u32 reg, u32 mask, u32 value)
+{
+	struct pci_dev *pci = to_pci_dev(bus->dev);
+	u32 data;
+
+	pci_read_config_dword(pci, reg, &data);
+	data &= ~mask;
+	data |= (value & mask);
+	pci_write_config_dword(pci, reg, data);
+}
+
+void avs_hda_power_gating_enable(struct avs_dev *adev, bool enable)
+{
+	u32 value;
+
+	value = enable ? 0 : AZX_PGCTL_LSRMD_MASK;
+	avs_hda_update_config_dword(&adev->base.core, AZX_PCIREG_PGCTL,
+				    AZX_PGCTL_LSRMD_MASK, value);
+}
+
+static void avs_hdac_clock_gating_enable(struct hdac_bus *bus, bool enable)
+{
+	u32 value;
+
+	value = enable ? AZX_CGCTL_MISCBDCGE_MASK : 0;
+	avs_hda_update_config_dword(bus, AZX_PCIREG_CGCTL,
+				    AZX_CGCTL_MISCBDCGE_MASK, value);
+}
+
+void avs_hda_clock_gating_enable(struct avs_dev *adev, bool enable)
+{
+	avs_hdac_clock_gating_enable(&adev->base.core, enable);
+}
+
+void avs_hda_l1sen_enable(struct avs_dev *adev, bool enable)
+{
+	u32 value;
+
+	value = enable ? AZX_VS_EM2_L1SEN : 0;
+	snd_hdac_chip_updatel(&adev->base.core, VS_EM2, AZX_VS_EM2_L1SEN, value);
+}
diff --git a/sound/soc/intel/avs/dsp.c b/sound/soc/intel/avs/dsp.c
index 5994d64d2468..a434e9918c51 100644
--- a/sound/soc/intel/avs/dsp.c
+++ b/sound/soc/intel/avs/dsp.c
@@ -198,6 +198,7 @@ int avs_dsp_init_module(struct avs_dev *adev, u16 module_id, u8 ppl_instance_id,
 			u16 *instance_id)
 {
 	struct avs_module_entry mentry;
+	bool was_loaded = false;
 	int ret, id;
 
 	id = avs_module_id_alloc(adev, module_id);
@@ -212,6 +213,16 @@ int avs_dsp_init_module(struct avs_dev *adev, u16 module_id, u8 ppl_instance_id,
 	if (ret)
 		goto err_mod_entry;
 
+	/* Load code into memory if this is the first instance. */
+	if (!id && !avs_module_entry_is_loaded(&mentry)) {
+		ret = avs_dsp_op(adev, transfer_mods, true, &mentry, 1);
+		if (ret) {
+			dev_err(adev->dev, "load modules failed: %d\n", ret);
+			goto err_mod_entry;
+		}
+		was_loaded = true;
+	}
+
 	ret = avs_ipc_init_instance(adev, module_id, id, ppl_instance_id,
 				    core_id, domain, param, param_size);
 	if (ret) {
@@ -223,6 +234,8 @@ int avs_dsp_init_module(struct avs_dev *adev, u16 module_id, u8 ppl_instance_id,
 	return 0;
 
 err_ipc:
+	if (was_loaded)
+		avs_dsp_op(adev, transfer_mods, false, &mentry, 1);
 	avs_dsp_put_core(adev, core_id);
 err_mod_entry:
 	avs_module_id_free(adev, module_id, id);
@@ -232,12 +245,25 @@ int avs_dsp_init_module(struct avs_dev *adev, u16 module_id, u8 ppl_instance_id,
 void avs_dsp_delete_module(struct avs_dev *adev, u16 module_id, u16 instance_id,
 			   u8 ppl_instance_id, u8 core_id)
 {
+	struct avs_module_entry mentry;
+	int ret;
+
 	/* Modules not owned by any pipeline need to be freed explicitly. */
 	if (ppl_instance_id == INVALID_PIPELINE_ID)
 		avs_ipc_delete_instance(adev, module_id, instance_id);
 
 	avs_module_id_free(adev, module_id, instance_id);
 
+	ret = avs_get_module_id_entry(adev, module_id, &mentry);
+	/* Unload occupied memory if this was the last instance. */
+	if (!ret && mentry.type.load_type == AVS_MODULE_LOAD_TYPE_LOADABLE) {
+		if (avs_is_module_ida_empty(adev, module_id)) {
+			ret = avs_dsp_op(adev, transfer_mods, false, &mentry, 1);
+			if (ret)
+				dev_err(adev->dev, "unload modules failed: %d\n", ret);
+		}
+	}
+
 	avs_dsp_put_core(adev, core_id);
 }
 
diff --git a/sound/soc/intel/avs/loader.c b/sound/soc/intel/avs/loader.c
new file mode 100644
index 000000000000..47e1f9a21e43
--- /dev/null
+++ b/sound/soc/intel/avs/loader.c
@@ -0,0 +1,237 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/firmware.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include "avs.h"
+#include "messages.h"
+#include "registers.h"
+
+#define AVS_FW_INIT_TIMEOUT_MS		3000
+
+#define AVS_ROOT_DIR			"intel/avs"
+#define AVS_BASEFW_FILENAME		"dsp_basefw.bin"
+#define AVS_EXT_MANIFEST_MAGIC		0x31454124
+#define SKL_MANIFEST_MAGIC		0x00000006
+#define SKL_ADSPFW_OFFSET		0x284
+
+/* Occasionally, engineering (release candidate) firmware is provided for testing. */
+static bool debug_ignore_fw_version;
+module_param_named(ignore_fw_version, debug_ignore_fw_version, bool, 0444);
+MODULE_PARM_DESC(ignore_fw_version, "Verify FW version 0=yes (default), 1=no");
+
+#define AVS_LIB_NAME_SIZE	8
+
+struct avs_fw_manifest {
+	u32 id;
+	u32 len;
+	char name[AVS_LIB_NAME_SIZE];
+	u32 preload_page_count;
+	u32 img_flags;
+	u32 feature_mask;
+	struct avs_fw_version version;
+} __packed;
+
+struct avs_fw_ext_manifest {
+	u32 id;
+	u32 len;
+	u16 version_major;
+	u16 version_minor;
+	u32 entries;
+} __packed;
+
+static int avs_fw_ext_manifest_strip(struct firmware *fw)
+{
+	struct avs_fw_ext_manifest *man;
+
+	if (fw->size < sizeof(*man))
+		return -EINVAL;
+
+	man = (struct avs_fw_ext_manifest *)fw->data;
+	if (man->id == AVS_EXT_MANIFEST_MAGIC) {
+		fw->data += man->len;
+		fw->size -= man->len;
+	}
+
+	return 0;
+}
+
+static int avs_fw_manifest_offset(struct firmware *fw)
+{
+	/* Header type found in first DWORD of fw binary. */
+	u32 magic = *(u32 *)fw->data;
+
+	switch (magic) {
+	case SKL_MANIFEST_MAGIC:
+		return SKL_ADSPFW_OFFSET;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int avs_fw_manifest_strip_verify(struct avs_dev *adev, struct firmware *fw,
+					const struct avs_fw_version *min)
+{
+	struct avs_fw_manifest *man;
+	int offset, ret;
+
+	ret = avs_fw_ext_manifest_strip(fw);
+	if (ret)
+		return ret;
+
+	offset = avs_fw_manifest_offset(fw);
+	if (offset < 0)
+		return offset;
+
+	if (fw->size < offset + sizeof(*man))
+		return -EINVAL;
+	if (!min)
+		return 0;
+
+	man = (struct avs_fw_manifest *)(fw->data + offset);
+	if (man->version.major != min->major ||
+	    man->version.minor != min->minor ||
+	    man->version.hotfix != min->hotfix ||
+	    man->version.build < min->build) {
+		dev_warn(adev->dev, "bad FW version %d.%d.%d.%d, expected %d.%d.%d.%d or newer\n",
+			 man->version.major, man->version.minor,
+			 man->version.hotfix, man->version.build,
+			 min->major, min->minor, min->hotfix, min->build);
+
+		if (!debug_ignore_fw_version)
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int avs_dsp_load_basefw(struct avs_dev *adev)
+{
+	const struct avs_fw_version *min_req;
+	const struct avs_spec *const spec = adev->spec;
+	const struct firmware *fw;
+	struct firmware stripped_fw;
+	char *filename;
+	int ret;
+
+	filename = kasprintf(GFP_KERNEL, "%s/%s/%s", AVS_ROOT_DIR, spec->name,
+			     AVS_BASEFW_FILENAME);
+	if (!filename)
+		return -ENOMEM;
+
+	ret = avs_request_firmware(adev, &fw, filename);
+	kfree(filename);
+	if (ret < 0) {
+		dev_err(adev->dev, "request firmware failed: %d\n", ret);
+		return ret;
+	}
+
+	stripped_fw = *fw;
+	min_req = &adev->spec->min_fw_version;
+
+	ret = avs_fw_manifest_strip_verify(adev, &stripped_fw, min_req);
+	if (ret < 0) {
+		dev_err(adev->dev, "invalid firmware data: %d\n", ret);
+		goto release_fw;
+	}
+
+	ret = avs_dsp_op(adev, load_basefw, &stripped_fw);
+	if (ret < 0) {
+		dev_err(adev->dev, "basefw load failed: %d\n", ret);
+		goto release_fw;
+	}
+
+	ret = wait_for_completion_timeout(&adev->fw_ready,
+					  msecs_to_jiffies(AVS_FW_INIT_TIMEOUT_MS));
+	if (!ret) {
+		dev_err(adev->dev, "firmware ready timeout\n");
+		avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK);
+		ret = -ETIMEDOUT;
+		goto release_fw;
+	}
+
+	return 0;
+
+release_fw:
+	avs_release_last_firmware(adev);
+	return ret;
+}
+
+int avs_dsp_boot_firmware(struct avs_dev *adev, bool purge)
+{
+	int ret, i;
+
+	/* Full boot, clear cached data except for basefw (slot 0). */
+	for (i = 1; i < adev->fw_cfg.max_libs_count; i++)
+		memset(adev->lib_names[i], 0, AVS_LIB_NAME_SIZE);
+
+	avs_hda_clock_gating_enable(adev, false);
+	avs_hda_l1sen_enable(adev, false);
+
+	ret = avs_dsp_load_basefw(adev);
+
+	avs_hda_l1sen_enable(adev, true);
+	avs_hda_clock_gating_enable(adev, true);
+
+	if (ret < 0)
+		return ret;
+
+	/* With all code loaded, refresh module information. */
+	ret = avs_module_info_init(adev, true);
+	if (ret) {
+		dev_err(adev->dev, "init module info failed: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+int avs_dsp_first_boot_firmware(struct avs_dev *adev)
+{
+	int ret, i;
+
+	ret = avs_dsp_boot_firmware(adev, true);
+	if (ret < 0) {
+		dev_err(adev->dev, "firmware boot failed: %d\n", ret);
+		return ret;
+	}
+
+	ret = avs_ipc_get_hw_config(adev, &adev->hw_cfg);
+	if (ret) {
+		dev_err(adev->dev, "get hw cfg failed: %d\n", ret);
+		return AVS_IPC_RET(ret);
+	}
+
+	ret = avs_ipc_get_fw_config(adev, &adev->fw_cfg);
+	if (ret) {
+		dev_err(adev->dev, "get fw cfg failed: %d\n", ret);
+		return AVS_IPC_RET(ret);
+	}
+
+	adev->core_refs = devm_kcalloc(adev->dev, adev->hw_cfg.dsp_cores,
+				       sizeof(*adev->core_refs), GFP_KERNEL);
+	adev->lib_names = devm_kcalloc(adev->dev, adev->fw_cfg.max_libs_count,
+				       sizeof(*adev->lib_names), GFP_KERNEL);
+	if (!adev->core_refs || !adev->lib_names)
+		return -ENOMEM;
+
+	for (i = 0; i < adev->fw_cfg.max_libs_count; i++) {
+		adev->lib_names[i] = devm_kzalloc(adev->dev, AVS_LIB_NAME_SIZE,
+						  GFP_KERNEL);
+		if (!adev->lib_names[i])
+			return -ENOMEM;
+	}
+
+	/* basefw always occupies slot 0 */
+	strcpy(&adev->lib_names[0][0], "BASEFW");
+
+	ida_init(&adev->ppl_ida);
+
+	return 0;
+}
diff --git a/sound/soc/intel/avs/registers.h b/sound/soc/intel/avs/registers.h
index 4bb10ca46a1e..a05465bac6d0 100644
--- a/sound/soc/intel/avs/registers.h
+++ b/sound/soc/intel/avs/registers.h
@@ -9,6 +9,12 @@
 #ifndef __SOUND_SOC_INTEL_AVS_REGS_H
 #define __SOUND_SOC_INTEL_AVS_REGS_H
 
+#define AZX_PCIREG_PGCTL		0x44
+#define AZX_PCIREG_CGCTL		0x48
+#define AZX_PGCTL_LSRMD_MASK		BIT(4)
+#define AZX_CGCTL_MISCBDCGE_MASK	BIT(6)
+#define AZX_VS_EM2_L1SEN		BIT(13)
+
 /* Intel HD Audio General DSP Registers */
 #define AVS_ADSP_GEN_BASE		0x0
 #define AVS_ADSP_REG_ADSPCS		(AVS_ADSP_GEN_BASE + 0x04)
-- 
2.25.1


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

* [PATCH v3 15/17] ASoC: Intel: avs: Implement CLDMA transfer
  2022-03-04 14:57 [PATCH v3 00/17] ASoC: Intel: AVS - Audio DSP for cAVS Cezary Rojewski
                   ` (13 preceding siblings ...)
  2022-03-04 14:57 ` [PATCH v3 14/17] ASoC: Intel: avs: General code loading flow Cezary Rojewski
@ 2022-03-04 14:57 ` Cezary Rojewski
  2022-03-04 14:57 ` [PATCH v3 16/17] ASoC: Intel: avs: Code loading over CLDMA Cezary Rojewski
  2022-03-04 14:57 ` [PATCH v3 17/17] ASoC: Intel: avs: Code loading over HDA Cezary Rojewski
  16 siblings, 0 replies; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-04 14:57 UTC (permalink / raw)
  To: alsa-devel
  Cc: Cezary Rojewski, rad, upstream, harshapriya.n, tiwai,
	pierre-louis.bossart, hdegoede, broonie, amadeuszx.slawinski,
	cujomalainey, lma

SKL and KBL rely on a dedicated HDAudio DMA stream for code loading and
authentication. The implementation of this specific mechanism for
SKL-based platforms re-uses HDAudio DMA (streaming) functions found in
HDA library to avoid duplication of functionality.

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/cldma.c     | 317 ++++++++++++++++++++++++++++++++
 sound/soc/intel/avs/cldma.h     |  29 +++
 sound/soc/intel/avs/registers.h |   2 +
 4 files changed, 349 insertions(+)
 create mode 100644 sound/soc/intel/avs/cldma.c
 create mode 100644 sound/soc/intel/avs/cldma.h

diff --git a/sound/soc/intel/avs/Makefile b/sound/soc/intel/avs/Makefile
index d9c793160612..f842bfc5e97e 100644
--- a/sound/soc/intel/avs/Makefile
+++ b/sound/soc/intel/avs/Makefile
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
 snd-soc-avs-objs := dsp.o ipc.o messages.o utils.o core.o loader.o
+snd-soc-avs-objs += cldma.o
 
 obj-$(CONFIG_SND_SOC_INTEL_AVS) += snd-soc-avs.o
diff --git a/sound/soc/intel/avs/cldma.c b/sound/soc/intel/avs/cldma.c
new file mode 100644
index 000000000000..8a1c59b5d7d0
--- /dev/null
+++ b/sound/soc/intel/avs/cldma.c
@@ -0,0 +1,317 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021 Intel Corporation. All rights reserved.
+//
+// Author: Cezary Rojewski <cezary.rojewski@intel.com>
+//
+
+#include <linux/pci.h>
+#include <sound/hda_register.h>
+#include <sound/hdaudio_ext.h>
+#include "cldma.h"
+#include "registers.h"
+
+/* Stream Registers */
+#define AZX_CL_SD_BASE			0x80
+#define AZX_SD_CTL_STRM_MASK		GENMASK(23, 20)
+#define AZX_SD_CTL_STRM(s) \
+	(((s)->stream_tag << 20) & AZX_SD_CTL_STRM_MASK)
+#define AZX_SD_BDLPL_BDLPLBA_MASK	GENMASK(31, 7)
+#define AZX_SD_BDLPL_BDLPLBA(lb)	((lb) & AZX_SD_BDLPL_BDLPLBA_MASK)
+
+/* Software Position Based FIFO Capability Registers */
+#define AZX_CL_SPBFCS			0x20
+#define AZX_REG_CL_SPBFCTL		(AZX_CL_SPBFCS + 0x4)
+#define AZX_REG_CL_SD_SPIB		(AZX_CL_SPBFCS + 0x8)
+
+#define AVS_CL_OP_INTERVAL_US		3
+#define AVS_CL_OP_TIMEOUT_US		300
+#define AVS_CL_IOC_TIMEOUT_MS		300
+#define AVS_CL_STREAM_INDEX		0
+
+struct hda_cldma {
+	struct device *dev;
+	struct hdac_bus *bus;
+	void __iomem *dsp_ba;
+
+	unsigned int buffer_size;
+	unsigned int num_periods;
+	unsigned int stream_tag;
+	void __iomem *sd_addr;
+
+	struct snd_dma_buffer dmab_data;
+	struct snd_dma_buffer dmab_bdl;
+	struct delayed_work memcpy_work;
+	struct completion completion;
+
+	/* runtime */
+	void *position;
+	unsigned int remaining;
+	unsigned int sd_status;
+};
+
+static void cldma_memcpy_work(struct work_struct *work);
+
+struct hda_cldma code_loader = {
+	.stream_tag	= AVS_CL_STREAM_INDEX + 1,
+	.memcpy_work	= __DELAYED_WORK_INITIALIZER(code_loader.memcpy_work, cldma_memcpy_work, 0),
+	.completion	= COMPLETION_INITIALIZER(code_loader.completion),
+};
+
+void hda_cldma_fill(struct hda_cldma *cl)
+{
+	unsigned int size, offset;
+
+	if (cl->remaining > cl->buffer_size)
+		size = cl->buffer_size;
+	else
+		size = cl->remaining;
+
+	offset = snd_hdac_stream_readl(cl, CL_SD_SPIB);
+	if (offset + size > cl->buffer_size) {
+		unsigned int ss;
+
+		ss = cl->buffer_size - offset;
+		memcpy(cl->dmab_data.area + offset, cl->position, ss);
+		offset = 0;
+		size -= ss;
+		cl->position += ss;
+		cl->remaining -= ss;
+	}
+
+	memcpy(cl->dmab_data.area + offset, cl->position, size);
+	cl->position += size;
+	cl->remaining -= size;
+
+	snd_hdac_stream_writel(cl, CL_SD_SPIB, offset + size);
+}
+
+static void cldma_memcpy_work(struct work_struct *work)
+{
+	struct hda_cldma *cl = container_of(work, struct hda_cldma, memcpy_work.work);
+	int ret;
+
+	ret = hda_cldma_start(cl);
+	if (ret < 0) {
+		dev_err(cl->dev, "cldma set RUN failed: %d\n", ret);
+		return;
+	}
+
+	while (true) {
+		ret = wait_for_completion_timeout(&cl->completion,
+						  msecs_to_jiffies(AVS_CL_IOC_TIMEOUT_MS));
+		if (!ret) {
+			dev_err(cl->dev, "cldma IOC timeout\n");
+			break;
+		}
+
+		if (!(cl->sd_status & SD_INT_COMPLETE)) {
+			dev_err(cl->dev, "cldma transfer error, SD status: 0x%08x\n",
+				cl->sd_status);
+			break;
+		}
+
+		if (!cl->remaining)
+			break;
+
+		reinit_completion(&cl->completion);
+		hda_cldma_fill(cl);
+		/* enable CLDMA interrupt */
+		snd_hdac_adsp_updatel(cl, AVS_ADSP_REG_ADSPIC, AVS_ADSP_ADSPIC_CLDMA,
+				      AVS_ADSP_ADSPIC_CLDMA);
+	}
+}
+
+void hda_cldma_transfer(struct hda_cldma *cl, unsigned long start_delay)
+{
+	if (!cl->remaining)
+		return;
+
+	reinit_completion(&cl->completion);
+	/* fill buffer with the first chunk before scheduling run */
+	hda_cldma_fill(cl);
+
+	schedule_delayed_work(&cl->memcpy_work, start_delay);
+}
+
+int hda_cldma_start(struct hda_cldma *cl)
+{
+	unsigned int reg;
+
+	/* enable interrupts */
+	snd_hdac_adsp_updatel(cl, AVS_ADSP_REG_ADSPIC, AVS_ADSP_ADSPIC_CLDMA,
+			      AVS_ADSP_ADSPIC_CLDMA);
+	snd_hdac_stream_updateb(cl, SD_CTL, SD_INT_MASK | SD_CTL_DMA_START,
+				SD_INT_MASK | SD_CTL_DMA_START);
+
+	/* await DMA engine start */
+	return snd_hdac_stream_readb_poll(cl, SD_CTL, reg, reg & SD_CTL_DMA_START,
+					  AVS_CL_OP_INTERVAL_US, AVS_CL_OP_TIMEOUT_US);
+}
+
+int hda_cldma_stop(struct hda_cldma *cl)
+{
+	unsigned int reg;
+	int ret;
+
+	/* disable interrupts */
+	snd_hdac_adsp_updatel(cl, AVS_ADSP_REG_ADSPIC, AVS_ADSP_ADSPIC_CLDMA, 0);
+	snd_hdac_stream_updateb(cl, SD_CTL, SD_INT_MASK | SD_CTL_DMA_START, 0);
+
+	/* await DMA engine stop */
+	ret = snd_hdac_stream_readb_poll(cl, SD_CTL, reg, !(reg & SD_CTL_DMA_START),
+					 AVS_CL_OP_INTERVAL_US, AVS_CL_OP_TIMEOUT_US);
+	cancel_delayed_work_sync(&cl->memcpy_work);
+
+	return ret;
+}
+
+int hda_cldma_reset(struct hda_cldma *cl)
+{
+	unsigned int reg;
+	int ret;
+
+	ret = hda_cldma_stop(cl);
+	if (ret < 0) {
+		dev_err(cl->dev, "cldma stop failed: %d\n", ret);
+		return ret;
+	}
+
+	snd_hdac_stream_updateb(cl, SD_CTL, 1, 1);
+	ret = snd_hdac_stream_readb_poll(cl, SD_CTL, reg, (reg & 1), AVS_CL_OP_INTERVAL_US,
+					 AVS_CL_OP_TIMEOUT_US);
+	if (ret < 0) {
+		dev_err(cl->dev, "cldma set SRST failed: %d\n", ret);
+		return ret;
+	}
+
+	snd_hdac_stream_updateb(cl, SD_CTL, 1, 0);
+	ret = snd_hdac_stream_readb_poll(cl, SD_CTL, reg, !(reg & 1), AVS_CL_OP_INTERVAL_US,
+					 AVS_CL_OP_TIMEOUT_US);
+	if (ret < 0) {
+		dev_err(cl->dev, "cldma unset SRST failed: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+void hda_cldma_set_data(struct hda_cldma *cl, void *data, unsigned int size)
+{
+	/* setup runtime */
+	cl->position = data;
+	cl->remaining = size;
+}
+
+static void cldma_setup_bdle(struct hda_cldma *cl, u32 bdle_size)
+{
+	struct snd_dma_buffer *dmab = &cl->dmab_data;
+	__le32 *bdl = (__le32 *)cl->dmab_bdl.area;
+	int remaining = cl->buffer_size;
+	int offset = 0;
+
+	cl->num_periods = 0;
+
+	while (remaining > 0) {
+		phys_addr_t addr;
+		int chunk;
+
+		addr = snd_sgbuf_get_addr(dmab, offset);
+		bdl[0] = cpu_to_le32(lower_32_bits(addr));
+		bdl[1] = cpu_to_le32(upper_32_bits(addr));
+		chunk = snd_sgbuf_get_chunk_size(dmab, offset, bdle_size);
+		bdl[2] = cpu_to_le32(chunk);
+
+		remaining -= chunk;
+		/* set IOC only for the last entry */
+		bdl[3] = (remaining > 0) ? 0 : cpu_to_le32(0x01);
+
+		bdl += 4;
+		offset += chunk;
+		cl->num_periods++;
+	}
+}
+
+void hda_cldma_setup(struct hda_cldma *cl)
+{
+	dma_addr_t bdl_addr = cl->dmab_bdl.addr;
+
+	cldma_setup_bdle(cl, cl->buffer_size / 2);
+
+	snd_hdac_stream_writel(cl, SD_BDLPL, AZX_SD_BDLPL_BDLPLBA(lower_32_bits(bdl_addr)));
+	snd_hdac_stream_writel(cl, SD_BDLPU, upper_32_bits(bdl_addr));
+
+	snd_hdac_stream_writel(cl, SD_CBL, cl->buffer_size);
+	snd_hdac_stream_writeb(cl, SD_LVI, cl->num_periods - 1);
+
+	snd_hdac_stream_updatel(cl, SD_CTL, AZX_SD_CTL_STRM_MASK, AZX_SD_CTL_STRM(cl));
+	/* enable spib */
+	snd_hdac_stream_writel(cl, CL_SPBFCTL, 1);
+}
+
+static irqreturn_t cldma_irq_handler(int irq, void *dev_id)
+{
+	struct hda_cldma *cl = dev_id;
+	u32 adspis;
+
+	adspis = snd_hdac_adsp_readl(cl, AVS_ADSP_REG_ADSPIS);
+	if (adspis == UINT_MAX)
+		return IRQ_NONE;
+	if (!(adspis & AVS_ADSP_ADSPIS_CLDMA))
+		return IRQ_NONE;
+
+	cl->sd_status = snd_hdac_stream_readb(cl, SD_STS);
+	dev_warn(cl->dev, "%s sd_status: 0x%08x\n", __func__, cl->sd_status);
+
+	/* disable CLDMA interrupt */
+	snd_hdac_adsp_updatel(cl, AVS_ADSP_REG_ADSPIC, AVS_ADSP_ADSPIC_CLDMA, 0);
+
+	complete(&cl->completion);
+
+	return IRQ_HANDLED;
+}
+
+int hda_cldma_init(struct hda_cldma *cl, struct hdac_bus *bus, void __iomem *dsp_ba,
+		   unsigned int buffer_size)
+{
+	struct pci_dev *pci = to_pci_dev(bus->dev);
+	int ret;
+
+	ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, bus->dev, buffer_size, &cl->dmab_data);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, bus->dev, BDL_SIZE, &cl->dmab_bdl);
+	if (ret < 0)
+		goto alloc_err;
+
+	cl->dev = bus->dev;
+	cl->bus = bus;
+	cl->dsp_ba = dsp_ba;
+	cl->buffer_size = buffer_size;
+	cl->sd_addr = dsp_ba + AZX_CL_SD_BASE;
+
+	ret = pci_request_irq(pci, 0, cldma_irq_handler, NULL, cl, "CLDMA");
+	if (ret < 0) {
+		dev_err(cl->dev, "Failed to request CLDMA IRQ handler: %d\n", ret);
+		goto req_err;
+	}
+
+	return 0;
+
+req_err:
+	snd_dma_free_pages(&cl->dmab_bdl);
+alloc_err:
+	snd_dma_free_pages(&cl->dmab_data);
+
+	return ret;
+}
+
+void hda_cldma_free(struct hda_cldma *cl)
+{
+	struct pci_dev *pci = to_pci_dev(cl->dev);
+
+	pci_free_irq(pci, 0, cl);
+	snd_dma_free_pages(&cl->dmab_data);
+	snd_dma_free_pages(&cl->dmab_bdl);
+}
diff --git a/sound/soc/intel/avs/cldma.h b/sound/soc/intel/avs/cldma.h
new file mode 100644
index 000000000000..cad81f03095a
--- /dev/null
+++ b/sound/soc/intel/avs/cldma.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright(c) 2021 Intel Corporation. All rights reserved.
+ *
+ * Author: Cezary Rojewski <cezary.rojewski@intel.com>
+ */
+
+#ifndef __SOUND_SOC_INTEL_AVS_CLDMA_H
+#define __SOUND_SOC_INTEL_AVS_CLDMA_H
+
+#define AVS_CL_DEFAULT_BUFFER_SIZE	(32 * PAGE_SIZE)
+
+struct hda_cldma;
+extern struct hda_cldma code_loader;
+
+void hda_cldma_fill(struct hda_cldma *cl);
+void hda_cldma_transfer(struct hda_cldma *cl, unsigned long start_delay);
+
+int hda_cldma_start(struct hda_cldma *cl);
+int hda_cldma_stop(struct hda_cldma *cl);
+int hda_cldma_reset(struct hda_cldma *cl);
+
+void hda_cldma_set_data(struct hda_cldma *cl, void *data, unsigned int size);
+void hda_cldma_setup(struct hda_cldma *cl);
+int hda_cldma_init(struct hda_cldma *cl, struct hdac_bus *bus, void __iomem *dsp_ba,
+		   unsigned int buffer_size);
+void hda_cldma_free(struct hda_cldma *cl);
+
+#endif
diff --git a/sound/soc/intel/avs/registers.h b/sound/soc/intel/avs/registers.h
index a05465bac6d0..0f55f526d962 100644
--- a/sound/soc/intel/avs/registers.h
+++ b/sound/soc/intel/avs/registers.h
@@ -22,7 +22,9 @@
 #define AVS_ADSP_REG_ADSPIS		(AVS_ADSP_GEN_BASE + 0x0C)
 
 #define AVS_ADSP_ADSPIC_IPC		BIT(0)
+#define AVS_ADSP_ADSPIC_CLDMA		BIT(1)
 #define AVS_ADSP_ADSPIS_IPC		BIT(0)
+#define AVS_ADSP_ADSPIS_CLDMA		BIT(1)
 
 #define AVS_ADSPCS_CRST_MASK(cm)	(cm)
 #define AVS_ADSPCS_CSTALL_MASK(cm)	((cm) << 8)
-- 
2.25.1


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

* [PATCH v3 16/17] ASoC: Intel: avs: Code loading over CLDMA
  2022-03-04 14:57 [PATCH v3 00/17] ASoC: Intel: AVS - Audio DSP for cAVS Cezary Rojewski
                   ` (14 preceding siblings ...)
  2022-03-04 14:57 ` [PATCH v3 15/17] ASoC: Intel: avs: Implement CLDMA transfer Cezary Rojewski
@ 2022-03-04 14:57 ` Cezary Rojewski
  2022-03-04 14:57 ` [PATCH v3 17/17] ASoC: Intel: avs: Code loading over HDA Cezary Rojewski
  16 siblings, 0 replies; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-04 14:57 UTC (permalink / raw)
  To: alsa-devel
  Cc: Cezary Rojewski, rad, upstream, harshapriya.n, tiwai,
	pierre-louis.bossart, hdegoede, broonie, amadeuszx.slawinski,
	cujomalainey, lma

With CLDMA transfer implemented, make use of it to shape firmware,
library and module loading routines for SKL and KBL platforms.

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    |   7 ++
 sound/soc/intel/avs/loader.c | 159 +++++++++++++++++++++++++++++++++++
 2 files changed, 166 insertions(+)

diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h
index 2527d6170417..fb3520f32488 100644
--- a/sound/soc/intel/avs/avs.h
+++ b/sound/soc/intel/avs/avs.h
@@ -44,6 +44,8 @@ struct avs_dsp_ops {
 #define avs_dsp_op(adev, op, ...) \
 	((adev)->spec->dsp_ops->op(adev, ## __VA_ARGS__))
 
+#define AVS_PLATATTR_CLDMA		BIT_ULL(0)
+
 #define avs_platattr_test(adev, attr) \
 	((adev)->spec->attributes & AVS_PLATATTR_##attr)
 
@@ -233,4 +235,9 @@ void avs_hda_l1sen_enable(struct avs_dev *adev, bool enable);
 int avs_dsp_boot_firmware(struct avs_dev *adev, bool purge);
 int avs_dsp_first_boot_firmware(struct avs_dev *adev);
 
+int avs_cldma_load_basefw(struct avs_dev *adev, struct firmware *fw);
+int avs_cldma_load_library(struct avs_dev *adev, struct firmware *lib, u32 id);
+int avs_cldma_transfer_modules(struct avs_dev *adev, bool load,
+			       struct avs_module_entry *mods, u32 num_mods);
+
 #endif /* __SOUND_SOC_INTEL_AVS_H */
diff --git a/sound/soc/intel/avs/loader.c b/sound/soc/intel/avs/loader.c
index 47e1f9a21e43..2134aaabe2c6 100644
--- a/sound/soc/intel/avs/loader.c
+++ b/sound/soc/intel/avs/loader.c
@@ -9,12 +9,24 @@
 #include <linux/firmware.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <sound/hdaudio_ext.h>
 #include "avs.h"
+#include "cldma.h"
 #include "messages.h"
 #include "registers.h"
 
+#define AVS_ROM_STS_MASK		0xFF
+#define AVS_ROM_INIT_DONE		0x1
+#define SKL_ROM_BASEFW_ENTERED		0xF
+#define AVS_ROM_INIT_POLLING_US		5
+#define SKL_ROM_INIT_TIMEOUT_US		1000000
+
+#define AVS_FW_INIT_POLLING_US		500
+#define AVS_FW_INIT_TIMEOUT_US		3000000
 #define AVS_FW_INIT_TIMEOUT_MS		3000
 
+#define AVS_CLDMA_START_DELAY_MS	100
+
 #define AVS_ROOT_DIR			"intel/avs"
 #define AVS_BASEFW_FILENAME		"dsp_basefw.bin"
 #define AVS_EXT_MANIFEST_MAGIC		0x31454124
@@ -111,6 +123,144 @@ static int avs_fw_manifest_strip_verify(struct avs_dev *adev, struct firmware *f
 	return 0;
 }
 
+int avs_cldma_load_basefw(struct avs_dev *adev, struct firmware *fw)
+{
+	struct hda_cldma *cl = &code_loader;
+	unsigned int reg;
+	int ret;
+
+	ret = avs_dsp_op(adev, power, AVS_MAIN_CORE_MASK, true);
+	if (ret < 0)
+		return ret;
+
+	ret = avs_dsp_op(adev, reset, AVS_MAIN_CORE_MASK, false);
+	if (ret < 0)
+		return ret;
+
+	ret = hda_cldma_reset(cl);
+	if (ret < 0) {
+		dev_err(adev->dev, "cldma reset failed: %d\n", ret);
+		return ret;
+	}
+	hda_cldma_setup(cl);
+
+	ret = avs_dsp_op(adev, stall, AVS_MAIN_CORE_MASK, false);
+	if (ret < 0)
+		return ret;
+
+	reinit_completion(&adev->fw_ready);
+	avs_dsp_op(adev, int_control, true);
+
+	/* await ROM init */
+	ret = snd_hdac_adsp_readl_poll(adev, AVS_FW_REG_STATUS(adev), reg,
+			(reg & AVS_ROM_INIT_DONE) == AVS_ROM_INIT_DONE,
+			AVS_ROM_INIT_POLLING_US, SKL_ROM_INIT_TIMEOUT_US);
+	if (ret < 0) {
+		dev_err(adev->dev, "rom init timeout: %d\n", ret);
+		avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK);
+		return ret;
+	}
+
+	hda_cldma_set_data(cl, (void *)fw->data, fw->size);
+	/* transfer firmware */
+	hda_cldma_transfer(cl, 0);
+	ret = snd_hdac_adsp_readl_poll(adev, AVS_FW_REG_STATUS(adev), reg,
+			(reg & AVS_ROM_STS_MASK) == SKL_ROM_BASEFW_ENTERED,
+			AVS_FW_INIT_POLLING_US, AVS_FW_INIT_TIMEOUT_US);
+	hda_cldma_stop(cl);
+	if (ret < 0) {
+		dev_err(adev->dev, "transfer fw failed: %d\n", ret);
+		avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK);
+		return ret;
+	}
+
+	return 0;
+}
+
+int avs_cldma_load_library(struct avs_dev *adev, struct firmware *lib, u32 id)
+{
+	struct hda_cldma *cl = &code_loader;
+	int ret;
+
+	hda_cldma_set_data(cl, (void *)lib->data, lib->size);
+	/* transfer modules manifest */
+	hda_cldma_transfer(cl, msecs_to_jiffies(AVS_CLDMA_START_DELAY_MS));
+
+	/* DMA id ignored as there is only ever one code-loader DMA */
+	ret = avs_ipc_load_library(adev, 0, id);
+	hda_cldma_stop(cl);
+
+	if (ret) {
+		ret = AVS_IPC_RET(ret);
+		dev_err(adev->dev, "transfer lib %d failed: %d\n", id, ret);
+	}
+
+	return ret;
+}
+
+static int avs_cldma_load_module(struct avs_dev *adev, struct avs_module_entry *mentry)
+{
+	struct hda_cldma *cl = &code_loader;
+	const struct firmware *mod;
+	char *mod_name;
+	int ret;
+
+	mod_name = kasprintf(GFP_KERNEL, "%s/%s/dsp_mod_%pUL.bin", AVS_ROOT_DIR,
+			     adev->spec->name, mentry->uuid.b);
+	if (!mod_name)
+		return -ENOMEM;
+
+	ret = avs_request_firmware(adev, &mod, mod_name);
+	kfree(mod_name);
+	if (ret < 0)
+		return ret;
+
+	hda_cldma_set_data(cl, (void *)mod->data, mod->size);
+	hda_cldma_transfer(cl, msecs_to_jiffies(AVS_CLDMA_START_DELAY_MS));
+	ret = avs_ipc_load_modules(adev, &mentry->module_id, 1);
+	hda_cldma_stop(cl);
+
+	if (ret) {
+		dev_err(adev->dev, "load module %d failed: %d\n", mentry->module_id, ret);
+		avs_release_last_firmware(adev);
+		return AVS_IPC_RET(ret);
+	}
+
+	return 0;
+}
+
+int avs_cldma_transfer_modules(struct avs_dev *adev, bool load,
+			       struct avs_module_entry *mods, u32 num_mods)
+{
+	u16 *mod_ids;
+	int ret, i;
+
+	/* Either load to DSP or unload them to free space. */
+	if (load) {
+		for (i = 0; i < num_mods; i++) {
+			ret = avs_cldma_load_module(adev, &mods[i]);
+			if (ret)
+				return ret;
+		}
+
+		return 0;
+	}
+
+	mod_ids = kcalloc(num_mods, sizeof(u16), GFP_KERNEL);
+	if (!mod_ids)
+		return -ENOMEM;
+
+	for (i = 0; i < num_mods; i++)
+		mod_ids[i] = mods[i].module_id;
+
+	ret = avs_ipc_unload_modules(adev, mod_ids, num_mods);
+	kfree(mod_ids);
+	if (ret)
+		return AVS_IPC_RET(ret);
+
+	return 0;
+}
+
 static int avs_dsp_load_basefw(struct avs_dev *adev)
 {
 	const struct avs_fw_version *min_req;
@@ -196,6 +346,15 @@ int avs_dsp_first_boot_firmware(struct avs_dev *adev)
 {
 	int ret, i;
 
+	if (avs_platattr_test(adev, CLDMA)) {
+		ret = hda_cldma_init(&code_loader, &adev->base.core,
+				     adev->dsp_ba, AVS_CL_DEFAULT_BUFFER_SIZE);
+		if (ret < 0) {
+			dev_err(adev->dev, "cldma init failed: %d\n", ret);
+			return ret;
+		}
+	}
+
 	ret = avs_dsp_boot_firmware(adev, true);
 	if (ret < 0) {
 		dev_err(adev->dev, "firmware boot failed: %d\n", ret);
-- 
2.25.1


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

* [PATCH v3 17/17] ASoC: Intel: avs: Code loading over HDA
  2022-03-04 14:57 [PATCH v3 00/17] ASoC: Intel: AVS - Audio DSP for cAVS Cezary Rojewski
                   ` (15 preceding siblings ...)
  2022-03-04 14:57 ` [PATCH v3 16/17] ASoC: Intel: avs: Code loading over CLDMA Cezary Rojewski
@ 2022-03-04 14:57 ` Cezary Rojewski
  2022-03-04 16:59   ` Ranjani Sridharan
  16 siblings, 1 reply; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-04 14:57 UTC (permalink / raw)
  To: alsa-devel
  Cc: Cezary Rojewski, rad, upstream, harshapriya.n, tiwai,
	pierre-louis.bossart, hdegoede, broonie, amadeuszx.slawinski,
	cujomalainey, lma

Compared to SKL and KBL, younger cAVS platforms are meant to re-use one
of HDAudio streams during boot procedure causing CLDMA to become
obsolete. Once transferred, given stream is returned to pool available
for audio streaming.

Module loading handler is dummy as library and module code became
inseparable in later firmware generations.

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    |   5 +
 sound/soc/intel/avs/loader.c | 211 +++++++++++++++++++++++++++++++++++
 3 files changed, 217 insertions(+)

diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index e9768c4aa1a9..d025ca0c77fa 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -215,6 +215,7 @@ config SND_SOC_INTEL_AVS
 	depends on COMMON_CLK
 	select SND_SOC_ACPI
 	select SND_HDA_EXT_CORE
+	select SND_HDA_DSP_LOADER
 	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 fb3520f32488..6dc5d17ccf21 100644
--- a/sound/soc/intel/avs/avs.h
+++ b/sound/soc/intel/avs/avs.h
@@ -45,6 +45,7 @@ struct avs_dsp_ops {
 	((adev)->spec->dsp_ops->op(adev, ## __VA_ARGS__))
 
 #define AVS_PLATATTR_CLDMA		BIT_ULL(0)
+#define AVS_PLATATTR_IMR		BIT_ULL(1)
 
 #define avs_platattr_test(adev, attr) \
 	((adev)->spec->attributes & AVS_PLATATTR_##attr)
@@ -239,5 +240,9 @@ int avs_cldma_load_basefw(struct avs_dev *adev, struct firmware *fw);
 int avs_cldma_load_library(struct avs_dev *adev, struct firmware *lib, u32 id);
 int avs_cldma_transfer_modules(struct avs_dev *adev, bool load,
 			       struct avs_module_entry *mods, u32 num_mods);
+int avs_hda_load_basefw(struct avs_dev *adev, struct firmware *fw);
+int avs_hda_load_library(struct avs_dev *adev, struct firmware *lib, u32 id);
+int avs_hda_transfer_modules(struct avs_dev *adev, bool load,
+			     struct avs_module_entry *mods, u32 num_mods);
 
 #endif /* __SOUND_SOC_INTEL_AVS_H */
diff --git a/sound/soc/intel/avs/loader.c b/sound/soc/intel/avs/loader.c
index 2134aaabe2c6..6520f23fc70e 100644
--- a/sound/soc/intel/avs/loader.c
+++ b/sound/soc/intel/avs/loader.c
@@ -9,6 +9,7 @@
 #include <linux/firmware.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <sound/hdaudio.h>
 #include <sound/hdaudio_ext.h>
 #include "avs.h"
 #include "cldma.h"
@@ -18,8 +19,11 @@
 #define AVS_ROM_STS_MASK		0xFF
 #define AVS_ROM_INIT_DONE		0x1
 #define SKL_ROM_BASEFW_ENTERED		0xF
+#define APL_ROM_FW_ENTERED		0x5
 #define AVS_ROM_INIT_POLLING_US		5
 #define SKL_ROM_INIT_TIMEOUT_US		1000000
+#define APL_ROM_INIT_TIMEOUT_US		300000
+#define APL_ROM_INIT_RETRIES		3
 
 #define AVS_FW_INIT_POLLING_US		500
 #define AVS_FW_INIT_TIMEOUT_US		3000000
@@ -261,6 +265,204 @@ int avs_cldma_transfer_modules(struct avs_dev *adev, bool load,
 	return 0;
 }
 
+static int
+avs_hda_init_rom(struct avs_dev *adev, unsigned int dma_id, bool purge)
+{
+	const struct avs_spec *const spec = adev->spec;
+	unsigned int corex_mask, reg;
+	int ret;
+
+	corex_mask = spec->core_init_mask & ~AVS_MAIN_CORE_MASK;
+
+	ret = avs_dsp_op(adev, power, spec->core_init_mask, true);
+	if (ret < 0)
+		goto err;
+
+	ret = avs_dsp_op(adev, reset, AVS_MAIN_CORE_MASK, false);
+	if (ret < 0)
+		goto err;
+
+	reinit_completion(&adev->fw_ready);
+	avs_dsp_op(adev, int_control, true);
+
+	/* set boot config */
+	ret = avs_ipc_set_boot_config(adev, dma_id, purge);
+	if (ret) {
+		ret = AVS_IPC_RET(ret);
+		goto err;
+	}
+
+	/* await ROM init */
+	ret = snd_hdac_adsp_readq_poll(adev, spec->rom_status, reg,
+				       (reg & 0xF) == AVS_ROM_INIT_DONE ||
+				       (reg & 0xF) == APL_ROM_FW_ENTERED,
+				       AVS_ROM_INIT_POLLING_US, APL_ROM_INIT_TIMEOUT_US);
+	if (ret < 0) {
+		dev_err(adev->dev, "rom init timeout: %d\n", ret);
+		goto err;
+	}
+
+	/* power down non-main cores */
+	if (corex_mask)
+		avs_dsp_op(adev, power, corex_mask, false);
+
+	return 0;
+
+err:
+	avs_dsp_core_disable(adev, spec->core_init_mask);
+	return ret;
+}
+
+static int avs_imr_load_basefw(struct avs_dev *adev)
+{
+	int ret;
+
+	/* DMA id ignored when flashing from IMR as no transfer occurs. */
+	ret = avs_hda_init_rom(adev, 0, false);
+	if (ret < 0) {
+		dev_err(adev->dev, "rom init failed: %d\n", ret);
+		return ret;
+	}
+
+	ret = wait_for_completion_timeout(&adev->fw_ready,
+				msecs_to_jiffies(AVS_FW_INIT_TIMEOUT_MS));
+	if (!ret) {
+		dev_err(adev->dev, "firmware ready timeout\n");
+		avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+int avs_hda_load_basefw(struct avs_dev *adev, struct firmware *fw)
+{
+	struct snd_pcm_substream substream;
+	struct snd_dma_buffer dmab;
+	struct hdac_ext_stream *estream;
+	struct hdac_stream *hstream;
+	struct hdac_bus *bus = &adev->base.core;
+	unsigned int sdfmt, reg;
+	int ret, i;
+
+	/* configure hda dma */
+	memset(&substream, 0, sizeof(substream));
+	substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
+	estream = snd_hdac_ext_stream_assign(bus, &substream,
+					     HDAC_EXT_STREAM_TYPE_HOST);
+	if (!estream)
+		return -ENODEV;
+	hstream = hdac_stream(estream);
+
+	/* code loading performed with default format */
+	sdfmt = snd_hdac_calc_stream_format(48000, 1, SNDRV_PCM_FORMAT_S32_LE, 32, 0);
+	ret = snd_hdac_dsp_prepare(hstream, sdfmt, fw->size, &dmab);
+	if (ret < 0)
+		goto release_stream;
+
+	/* enable SPIB for hda stream */
+	snd_hdac_ext_stream_spbcap_enable(bus, true, hstream->index);
+	ret = snd_hdac_ext_stream_set_spib(bus, estream, fw->size);
+	if (ret)
+		goto cleanup_resources;
+
+	memcpy(dmab.area, fw->data, fw->size);
+
+	for (i = 0; i < APL_ROM_INIT_RETRIES; i++) {
+		unsigned int dma_id = hstream->stream_tag - 1;
+
+		ret = avs_hda_init_rom(adev, dma_id, true);
+		if (!ret)
+			break;
+		dev_info(adev->dev, "#%d rom init fail: %d\n", i + 1, ret);
+	}
+	if (ret < 0)
+		goto cleanup_resources;
+
+	/* transfer firmware */
+	snd_hdac_dsp_trigger(hstream, true);
+	ret = snd_hdac_adsp_readl_poll(adev, AVS_FW_REG_STATUS(adev), reg,
+				       (reg & AVS_ROM_STS_MASK) == APL_ROM_FW_ENTERED,
+				       AVS_FW_INIT_POLLING_US, AVS_FW_INIT_TIMEOUT_US);
+	snd_hdac_dsp_trigger(hstream, false);
+	if (ret < 0) {
+		dev_err(adev->dev, "transfer fw failed: %d\n", ret);
+		avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK);
+	}
+
+cleanup_resources:
+	/* disable SPIB for hda stream */
+	snd_hdac_ext_stream_spbcap_enable(bus, false, hstream->index);
+	snd_hdac_ext_stream_set_spib(bus, estream, 0);
+
+	snd_hdac_dsp_cleanup(hstream, &dmab);
+release_stream:
+	snd_hdac_ext_stream_release(estream, HDAC_EXT_STREAM_TYPE_HOST);
+
+	return ret;
+}
+
+int avs_hda_load_library(struct avs_dev *adev, struct firmware *lib, u32 id)
+{
+	struct snd_pcm_substream substream;
+	struct snd_dma_buffer dmab;
+	struct hdac_ext_stream *estream;
+	struct hdac_stream *stream;
+	struct hdac_bus *bus = &adev->base.core;
+	unsigned int sdfmt;
+	int ret;
+
+	/* configure hda dma */
+	memset(&substream, 0, sizeof(substream));
+	substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
+	estream = snd_hdac_ext_stream_assign(bus, &substream,
+					     HDAC_EXT_STREAM_TYPE_HOST);
+	if (!estream)
+		return -ENODEV;
+	stream = hdac_stream(estream);
+
+	/* code loading performed with default format */
+	sdfmt = snd_hdac_calc_stream_format(48000, 1, SNDRV_PCM_FORMAT_S32_LE, 32, 0);
+	ret = snd_hdac_dsp_prepare(stream, sdfmt, lib->size, &dmab);
+	if (ret < 0)
+		goto release_stream;
+
+	/* enable SPIB for hda stream */
+	snd_hdac_ext_stream_spbcap_enable(bus, true, stream->index);
+	snd_hdac_ext_stream_set_spib(bus, estream, lib->size);
+
+	memcpy(dmab.area, lib->data, lib->size);
+
+	/* transfer firmware */
+	snd_hdac_dsp_trigger(stream, true);
+	ret = avs_ipc_load_library(adev, stream->stream_tag - 1, id);
+	snd_hdac_dsp_trigger(stream, false);
+	if (ret) {
+		dev_err(adev->dev, "transfer lib %d failed: %d\n", id, ret);
+		ret = AVS_IPC_RET(ret);
+	}
+
+	/* disable SPIB for hda stream */
+	snd_hdac_ext_stream_spbcap_enable(bus, false, stream->index);
+	snd_hdac_ext_stream_set_spib(bus, estream, 0);
+
+	snd_hdac_dsp_cleanup(stream, &dmab);
+release_stream:
+	snd_hdac_ext_stream_release(estream, HDAC_EXT_STREAM_TYPE_HOST);
+
+	return ret;
+}
+
+int avs_hda_transfer_modules(struct avs_dev *adev, bool load,
+			     struct avs_module_entry *mods, u32 num_mods)
+{
+	/*
+	 * All platforms without CLDMA are equipped with IMR,
+	 * and thus the module transferring is offloaded to DSP.
+	 */
+	return 0;
+}
+
 static int avs_dsp_load_basefw(struct avs_dev *adev)
 {
 	const struct avs_fw_version *min_req;
@@ -317,6 +519,15 @@ int avs_dsp_boot_firmware(struct avs_dev *adev, bool purge)
 {
 	int ret, i;
 
+	/* Forgo full boot if flash from IMR succeeds. */
+	if (!purge && avs_platattr_test(adev, IMR)) {
+		ret = avs_imr_load_basefw(adev);
+		if (!ret)
+			return 0;
+
+		dev_dbg(adev->dev, "firmware flash from imr failed: %d\n", ret);
+	}
+
 	/* Full boot, clear cached data except for basefw (slot 0). */
 	for (i = 1; i < adev->fw_cfg.max_libs_count; i++)
 		memset(adev->lib_names[i], 0, AVS_LIB_NAME_SIZE);
-- 
2.25.1


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

* Re: [PATCH v3 03/17] ASoC: Intel: Introduce AVS driver
  2022-03-04 14:57 ` [PATCH v3 03/17] ASoC: Intel: Introduce AVS driver Cezary Rojewski
@ 2022-03-04 15:51   ` Ranjani Sridharan
  2022-03-04 16:43     ` Cezary Rojewski
  0 siblings, 1 reply; 65+ messages in thread
From: Ranjani Sridharan @ 2022-03-04 15:51 UTC (permalink / raw)
  To: Cezary Rojewski, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

On Fri, 2022-03-04 at 15:57 +0100, Cezary Rojewski wrote:
> Declare base structures and core DSP operations for the avs solution.
> The base structures describe PCI HDAudio bus device and platform-type
> differentiations. First set of operations added controls the
> lifecycle
> of any Audio DSP core: (un)powering, (un)resetting and (un)stalling.
> 
> 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         |  11 ++++
>  sound/soc/intel/Makefile        |   1 +
>  sound/soc/intel/avs/Makefile    |   5 ++
>  sound/soc/intel/avs/avs.h       |  71 +++++++++++++++++++++
>  sound/soc/intel/avs/dsp.c       | 107
> ++++++++++++++++++++++++++++++++
>  sound/soc/intel/avs/registers.h |  22 +++++++
>  6 files changed, 217 insertions(+)
>  create mode 100644 sound/soc/intel/avs/Makefile
>  create mode 100644 sound/soc/intel/avs/avs.h
>  create mode 100644 sound/soc/intel/avs/dsp.c
>  create mode 100644 sound/soc/intel/avs/registers.h
> 
> diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
> index f3a4a907b29d..e9768c4aa1a9 100644
> --- a/sound/soc/intel/Kconfig
> +++ b/sound/soc/intel/Kconfig
> @@ -209,5 +209,16 @@ config SND_SOC_INTEL_KEEMBAY
>  	  If you have a Intel Keembay platform then enable this option
>  	  by saying Y or m.
>  
> +config SND_SOC_INTEL_AVS
> +	tristate "Intel AVS driver"
> +	depends on PCI && ACPI
> +	depends on COMMON_CLK
> +	select SND_SOC_ACPI
> +	select SND_HDA_EXT_CORE
> +	help
> +	  Enable support for Intel(R) cAVS 1.5 platforms with DSP
> +	  capabilities. This includes Skylake, Kabylake, Amberlake and
> +	  Apollolake.
> +
>  # ASoC codec drivers
>  source "sound/soc/intel/boards/Kconfig"
> diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile
> index 7c5038803be7..d44b2652c707 100644
> --- a/sound/soc/intel/Makefile
> +++ b/sound/soc/intel/Makefile
> @@ -7,6 +7,7 @@ obj-$(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM) += atom/
>  obj-$(CONFIG_SND_SOC_INTEL_CATPT) += catpt/
>  obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE_COMMON) += skylake/
>  obj-$(CONFIG_SND_SOC_INTEL_KEEMBAY) += keembay/
> +obj-$(CONFIG_SND_SOC_INTEL_AVS) += avs/
>  
>  # Machine support
>  obj-$(CONFIG_SND_SOC) += boards/
> diff --git a/sound/soc/intel/avs/Makefile
> b/sound/soc/intel/avs/Makefile
> new file mode 100644
> index 000000000000..5f7976a95fe2
> --- /dev/null
> +++ b/sound/soc/intel/avs/Makefile
> @@ -0,0 +1,5 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +
> +snd-soc-avs-objs := dsp.o
> +
> +obj-$(CONFIG_SND_SOC_INTEL_AVS) += snd-soc-avs.o
> diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h
> new file mode 100644
> index 000000000000..d4e6310e4bf7
> --- /dev/null
> +++ b/sound/soc/intel/avs/avs.h
> @@ -0,0 +1,71 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright(c) 2021 Intel Corporation. All rights reserved.
> + *
> + * Authors: Cezary Rojewski <cezary.rojewski@intel.com>
> + *          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
> + */
> +
> +#ifndef __SOUND_SOC_INTEL_AVS_H
> +#define __SOUND_SOC_INTEL_AVS_H
> +
> +#include <linux/device.h>
> +#include <sound/hda_codec.h>
> +
> +struct avs_dev;
> +
> +struct avs_dsp_ops {
> +	int (* const power)(struct avs_dev *, u32, bool);
> +	int (* const reset)(struct avs_dev *, u32, bool);
> +	int (* const stall)(struct avs_dev *, u32, bool);
> +};
> +
> +#define avs_dsp_op(adev, op, ...) \
> +	((adev)->spec->dsp_ops->op(adev, ## __VA_ARGS__))
> +
> +#define avs_platattr_test(adev, attr) \
> +	((adev)->spec->attributes & AVS_PLATATTR_##attr)
AVS_PLATATTR_* don't seem to be defined in this patch?

Thanks,
Ranjani


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

* Re: [PATCH v3 04/17] ASoC: Intel: avs: Inter process communication
  2022-03-04 14:57 ` [PATCH v3 04/17] ASoC: Intel: avs: Inter process communication Cezary Rojewski
@ 2022-03-04 16:09   ` Ranjani Sridharan
  2022-03-04 17:11     ` Cezary Rojewski
  0 siblings, 1 reply; 65+ messages in thread
From: Ranjani Sridharan @ 2022-03-04 16:09 UTC (permalink / raw)
  To: Cezary Rojewski, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

On Fri, 2022-03-04 at 15:57 +0100, Cezary Rojewski wrote:
> Implement the IPC between Intel audio firmware and kernel driver. The
> IPC allows transmission of requests, handling of responses as well as
> unsolicited (i.e. firmware-generated) notifications.
> 
> A subscription mechanism is added to enable different parts of the
> driver to register for specific notifications.
> 
> The part of the DSP boot process that involves sending ROM message
> requires an extra step - must be followed by unstall operation of
> MAIN_CORE. All other types of messages do not require such specific
> handling, so separate set of functions is provided for sending these.
> 
> 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       | 100 +++++++++
>  sound/soc/intel/avs/ipc.c       | 387
> ++++++++++++++++++++++++++++++++
>  sound/soc/intel/avs/messages.h  | 170 ++++++++++++++
>  sound/soc/intel/avs/registers.h |  45 ++++
>  5 files changed, 703 insertions(+), 1 deletion(-)
>  create mode 100644 sound/soc/intel/avs/ipc.c
>  create mode 100644 sound/soc/intel/avs/messages.h
> 
> diff --git a/sound/soc/intel/avs/Makefile
> b/sound/soc/intel/avs/Makefile
> index 5f7976a95fe2..e243806dd38a 100644
> --- a/sound/soc/intel/avs/Makefile
> +++ b/sound/soc/intel/avs/Makefile
> @@ -1,5 +1,5 @@
>  # SPDX-License-Identifier: GPL-2.0-only
>  
> -snd-soc-avs-objs := dsp.o
> +snd-soc-avs-objs := dsp.o ipc.o
>  
>  obj-$(CONFIG_SND_SOC_INTEL_AVS) += snd-soc-avs.o
> diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h
> index d4e6310e4bf7..841b8541b101 100644
> --- a/sound/soc/intel/avs/avs.h
> +++ b/sound/soc/intel/avs/avs.h
> @@ -11,13 +11,27 @@
>  
>  #include <linux/device.h>
>  #include <sound/hda_codec.h>
> +#include "messages.h"
>  
>  struct avs_dev;
>  
> +/*
> + * struct avs_dsp_ops - Platform-specific DSP operations
> + *
> + * @power: Power on or off DSP cores
> + * @reset: Enter or exit reset state on DSP cores
> + * @stall: Stall or run DSP cores
> + * @irq_handler: Top half of IPC servicing
> + * @irq_thread: Bottom half of IPC servicing
> + * @int_control: Enable or disable IPC interrupts
> + */
>  struct avs_dsp_ops {
>  	int (* const power)(struct avs_dev *, u32, bool);
>  	int (* const reset)(struct avs_dev *, u32, bool);
>  	int (* const stall)(struct avs_dev *, u32, bool);
> +	irqreturn_t (* const irq_handler)(int, void *);
> +	irqreturn_t (* const irq_thread)(int, void *);
> +	void (* const int_control)(struct avs_dev *, bool);
>  };
>  
>  #define avs_dsp_op(adev, op, ...) \
> @@ -34,6 +48,9 @@ struct avs_spec {
>  
>  	const u32 core_init_mask;	/* used during DSP boot */
>  	const u64 attributes;		/* bitmask of AVS_PLATATTR_*
> */
> +	const u32 sram_base_offset;
> +	const u32 sram_window_size;
> +	const u32 rom_status;
>  };
>  
>  /*
> @@ -49,6 +66,9 @@ struct avs_dev {
>  
>  	void __iomem *dsp_ba;
>  	const struct avs_spec *spec;
> +	struct avs_ipc *ipc;
> +
> +	struct completion fw_ready;
>  };
>  
>  /* from hda_bus to avs_dev */
> @@ -68,4 +88,84 @@ int avs_dsp_core_stall(struct avs_dev *adev, u32
> core_mask, bool stall);
>  int avs_dsp_core_enable(struct avs_dev *adev, u32 core_mask);
>  int avs_dsp_core_disable(struct avs_dev *adev, u32 core_mask);
>  
> +/* Inter Process Communication */
> +
> +struct avs_ipc_msg {
> +	union {
> +		u64 header;
> +		union avs_global_msg glb;
> +		union avs_reply_msg rsp;
> +	};
> +	void *data;
> +	size_t size;
> +};
> +
> +/*
> + * struct avs_ipc - DSP IPC context
> + *
> + * @dev: PCI device
> + * @rx: Reply message cache
> + * @default_timeout_ms: default message timeout in MS
> + * @ready: whether firmware is ready and communication is open
> + * @rx_completed: whether RX for previously sent TX has been
> received
> + * @rx_lock: for serializating manipulation of rx_* fields
> + * @msg_lock: for synchronizing request handling
> + * @done_completion: DONE-part of IPC i.e. ROM and ACKs from FW
> + * @busy_completion: BUSY-part of IPC i.e. receiving responses from
> FW
> + */
> +struct avs_ipc {
> +	struct device *dev;
> +
> +	struct avs_ipc_msg rx;
> +	u32 default_timeout_ms;
> +	bool ready;
> +
> +	bool rx_completed;
> +	spinlock_t rx_lock;
> +	struct mutex msg_mutex;
> +	struct completion done_completion;
> +	struct completion busy_completion;
> +};
> +
> +#define AVS_EIPC	EREMOTEIO
> +/*
> + * IPC handlers may return positive value (firmware error code) what
> denotes
> + * successful HOST <-> DSP communication yet failure to process
> specific request.
> + *
> + * Below macro converts returned value to linux kernel error code.
> + * All IPC callers MUST use it as soon as firmware error code is
> consumed.
> + */
> +#define AVS_IPC_RET(ret) \
> +	(((ret) <= 0) ? (ret) : -AVS_EIPC)
> +
> +static inline void avs_ipc_err(struct avs_dev *adev, struct
> avs_ipc_msg *tx,
> +			       const char *name, int error)
> +{
> +	/*
> +	 * If IPC channel is blocked e.g.: due to ongoing recovery,
Do you mean firmware recovery? In which cases do you perform a
recovery?
> +	 * -EPERM error code is expected and thus it's not an actual
> error.
And what happens in this case? do you retry the IPC after recovery?
> +	 */
> +	if (error == -EPERM)
> +		dev_dbg(adev->dev, "%s 0x%08x 0x%08x failed: %d\n",
> name,
> +			tx->glb.primary, tx->glb.ext.val, error);
> +	else
> +		dev_err(adev->dev, "%s 0x%08x 0x%08x failed: %d\n",
> name,
> +			tx->glb.primary, tx->glb.ext.val, error);
> +}
> +
> +irqreturn_t avs_dsp_irq_handler(int irq, void *dev_id);
> +irqreturn_t avs_dsp_irq_thread(int irq, void *dev_id);
> +void avs_dsp_process_response(struct avs_dev *adev, u64 header);
> +int avs_dsp_send_msg_timeout(struct avs_dev *adev,
> +			     struct avs_ipc_msg *request,
> +			     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);
> +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);
> +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);
> +
>  #endif /* __SOUND_SOC_INTEL_AVS_H */
> diff --git a/sound/soc/intel/avs/ipc.c b/sound/soc/intel/avs/ipc.c
> new file mode 100644
> index 000000000000..c0722f8b195f
> --- /dev/null
> +++ b/sound/soc/intel/avs/ipc.c
> @@ -0,0 +1,387 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +//
> +// Copyright(c) 2021 Intel Corporation. All rights reserved.
> +//
> +// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
> +//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
> +//
> +
> +#include <linux/slab.h>
> +#include <sound/hdaudio_ext.h>
> +#include "avs.h"
> +#include "messages.h"
> +#include "registers.h"
> +
> +#define AVS_IPC_TIMEOUT_MS	300
> +
> +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);
> +
> +	ipc->rx.header = header;
> +	/* Abort copying payload if request processing was
> unsuccessful. */
This seems misplaced? Why would you called this function is the status
showed an error?

> +	if (!msg.status)
> +		memcpy_fromio(ipc->rx.data, avs_uplink_addr(adev),
> +			      ipc->rx.size);
> +}
> +
> +static void avs_dsp_process_notification(struct avs_dev *adev, u64
> header)
> +{
> +	struct avs_notify_mod_data mod_data;
> +	union avs_notify_msg msg = AVS_MSG(header);
> +	size_t data_size = 0;
> +	void *data = NULL;
> +
> +	/* Ignore spurious notifications until handshake is
> established. */
> +	if (!adev->ipc->ready && msg.notify_msg_type !=
> AVS_NOTIFY_FW_READY) {
> +		dev_dbg(adev->dev, "FW not ready, skip notification:
> 0x%08x\n",
> +			msg.primary);
> +		return;
> +	}
> +
> +	/* Calculate notification payload size. */
> +	switch (msg.notify_msg_type) {
> +	case AVS_NOTIFY_FW_READY:
> +		break;
> +
> +	case AVS_NOTIFY_PHRASE_DETECTED:
> +		data_size = sizeof(struct avs_notify_voice_data);
> +		break;
> +
> +	case AVS_NOTIFY_RESOURCE_EVENT:
> +		data_size = sizeof(struct avs_notify_res_data);
> +		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));
> +		data_size = sizeof(mod_data) + mod_data.data_size;
> +		break;
> +
> +	default:
> +		dev_info(adev->dev, "unknown notification: 0x%08x\n",
> +			 msg.primary);
info? should it be a warning?
> +		break;
> +	}
> +
> +	if (data_size) {
> +		data = kmalloc(data_size, GFP_KERNEL);
> +		if (!data)
> +			return;
Should this function be modified to return the error? If it failed
here, all subsequent IPC's rec'd will also fail isnt it?
> +
> +		memcpy_fromio(data, avs_uplink_addr(adev), data_size);
> +	}
> +
> +	/* Perform notification-specific operations. */
> +	switch (msg.notify_msg_type) {
> +	case AVS_NOTIFY_FW_READY:
> +		dev_dbg(adev->dev, "FW READY 0x%08x\n", msg.primary);
> +		adev->ipc->ready = true;
> +		complete(&adev->fw_ready);
> +		break;
> +
> +	default:
> +		break;
> +	}
> +
> +	kfree(data);
You alloc memory for "data", copy the data and free it? Where is it
used?
> +}
> +
> +void avs_dsp_process_response(struct avs_dev *adev, u64 header)
> +{
> +	struct avs_ipc *ipc = adev->ipc;
> +
> +	/*
> +	 * Response may either be solicited - a reply for a request
> that has
> +	 * been sent beforehand - or unsolicited (notification).
> +	 */
> +	if (avs_msg_is_reply(header)) {
> +		/* Response processing is invoked from IRQ thread. */
> +		spin_lock_irq(&ipc->rx_lock);
> +		avs_dsp_receive_rx(adev, header);
> +		ipc->rx_completed = true;
> +		spin_unlock_irq(&ipc->rx_lock);
> +	} else {
> +		avs_dsp_process_notification(adev, header);
> +	}
> +
> +	complete(&ipc->busy_completion);
> +}
> +
> +irqreturn_t avs_dsp_irq_handler(int irq, void *dev_id)
> +{
> +	struct avs_dev *adev = dev_id;
> +	struct avs_ipc *ipc = adev->ipc;
> +	u32 adspis, hipc_rsp, hipc_ack;
> +	irqreturn_t ret = IRQ_NONE;
> +
> +	adspis = snd_hdac_adsp_readl(adev, AVS_ADSP_REG_ADSPIS);
> +	if (adspis == UINT_MAX || !(adspis & AVS_ADSP_ADSPIS_IPC))
> +		return ret;
> +
> +	hipc_ack = snd_hdac_adsp_readl(adev, SKL_ADSP_REG_HIPCIE);
> +	hipc_rsp = snd_hdac_adsp_readl(adev, SKL_ADSP_REG_HIPCT);
> +
> +	/* DSP acked host's request */
> +	if (hipc_ack & SKL_ADSP_HIPCIE_DONE) {
> +		/*
> +		 * As an extra precaution, mask done interrupt. Code
> executed
> +		 * due to complete() found below does not assume any
> masking.
> +		 */
> +		snd_hdac_adsp_updatel(adev, SKL_ADSP_REG_HIPCCTL,
> +				      AVS_ADSP_HIPCCTL_DONE, 0);
> +
> +		complete(&ipc->done_completion);
> +
> +		/* tell DSP it has our attention */
> +		snd_hdac_adsp_updatel(adev, SKL_ADSP_REG_HIPCIE,
> +				      SKL_ADSP_HIPCIE_DONE,
> +				      SKL_ADSP_HIPCIE_DONE);
> +		/* unmask done interrupt */
> +		snd_hdac_adsp_updatel(adev, SKL_ADSP_REG_HIPCCTL,
> +				      AVS_ADSP_HIPCCTL_DONE,
> +				      AVS_ADSP_HIPCCTL_DONE);
> +		ret = IRQ_HANDLED;
> +	}
> +
> +	/* DSP sent new response to process */
> +	if (hipc_rsp & SKL_ADSP_HIPCT_BUSY) {
> +		/* mask busy interrupt */
> +		snd_hdac_adsp_updatel(adev, SKL_ADSP_REG_HIPCCTL,
> +				      AVS_ADSP_HIPCCTL_BUSY, 0);
> +
> +		ret = IRQ_WAKE_THREAD;
> +	}
> +
> +	return ret;
> +}
> +
> +irqreturn_t avs_dsp_irq_thread(int irq, void *dev_id)
> +{
> +	struct avs_dev *adev = dev_id;
> +	union avs_reply_msg msg;
> +	u32 hipct, hipcte;
> +
> +	hipct = snd_hdac_adsp_readl(adev, SKL_ADSP_REG_HIPCT);
> +	hipcte = snd_hdac_adsp_readl(adev, SKL_ADSP_REG_HIPCTE);
> +
> +	/* ensure DSP sent new response to process */
> +	if (!(hipct & SKL_ADSP_HIPCT_BUSY))
> +		return IRQ_NONE;
> +
> +	msg.primary = hipct;
> +	msg.ext.val = hipcte;
> +	avs_dsp_process_response(adev, msg.val);
> +
> +	/* tell DSP we accepted its message */
> +	snd_hdac_adsp_updatel(adev, SKL_ADSP_REG_HIPCT,
> +			      SKL_ADSP_HIPCT_BUSY,
> SKL_ADSP_HIPCT_BUSY);
> +	/* unmask busy interrupt */
> +	snd_hdac_adsp_updatel(adev, SKL_ADSP_REG_HIPCCTL,
> +			      AVS_ADSP_HIPCCTL_BUSY,
> AVS_ADSP_HIPCCTL_BUSY);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static bool avs_ipc_is_busy(struct avs_ipc *ipc)
> +{
> +	struct avs_dev *adev = to_avs_dev(ipc->dev);
> +	u32 hipc_rsp;
> +
> +	hipc_rsp = snd_hdac_adsp_readl(adev, SKL_ADSP_REG_HIPCT);
> +	return hipc_rsp & SKL_ADSP_HIPCT_BUSY;
> +}
> +
> +static int avs_ipc_wait_busy_completion(struct avs_ipc *ipc, int
> timeout)
> +{
> +	u32 repeats_left = 128; /* to avoid infinite looping */
> +	int ret;
> +
> +again:
> +	ret = wait_for_completion_timeout(&ipc->busy_completion,
> +					  msecs_to_jiffies(timeout));
> +
> +	/* DSP could be unresponsive at this point. */
> +	if (!ipc->ready)
> +		return -EPERM;
> +
> +	if (!ret) {
> +		if (!avs_ipc_is_busy(ipc))
> +			return -ETIMEDOUT;
> +		/*
> +		 * Firmware did its job, either notification or reply
> +		 * has been received - now wait until it's processed.
> +		 */
> +		wait_for_completion_killable(&ipc->busy_completion);
> +	}
> +
> +	/* Ongoing notification's bottom-half may cause early wakeup */
> +	spin_lock(&ipc->rx_lock);
> +	if (!ipc->rx_completed) {
> +		if (repeats_left) {
> +			/* Reply delayed due to notification. */
> +			repeats_left--;
> +			reinit_completion(&ipc->busy_completion);
> +			spin_unlock(&ipc->rx_lock);
> +			goto again;
> +		}
> +
> +		spin_unlock(&ipc->rx_lock);
> +		return -ETIMEDOUT;
> +	}
> +
> +	spin_unlock(&ipc->rx_lock);
> +	return 0;
> +}
> +
> +static void avs_ipc_msg_init(struct avs_ipc *ipc, struct avs_ipc_msg
> *reply)
> +{
> +	lockdep_assert_held(&ipc->rx_lock);
> +
> +	ipc->rx.header = 0;
> +	ipc->rx.size = reply ? reply->size : 0;
> +	ipc->rx_completed = false;
> +
> +	reinit_completion(&ipc->done_completion);
> +	reinit_completion(&ipc->busy_completion);
> +}
> +
> +static void avs_dsp_send_tx(struct avs_dev *adev, struct avs_ipc_msg
> *tx)
send_tx? send and tx both imply the same isnt it? maybe just use one or
the other?
> +{
> +	tx->header |= SKL_ADSP_HIPCI_BUSY;
> +
> +	if (tx->size)
> +		memcpy_toio(avs_downlink_addr(adev), tx->data, tx-
> >size);
> +	snd_hdac_adsp_writel(adev, SKL_ADSP_REG_HIPCIE, tx->header >>
> 32);
> +	snd_hdac_adsp_writel(adev, SKL_ADSP_REG_HIPCI, tx->header &
> UINT_MAX);
> +}
> +
> +static int avs_dsp_do_send_msg(struct avs_dev *adev, struct
> avs_ipc_msg *request,
> +			       struct avs_ipc_msg *reply, int timeout)
> +{
> +	struct avs_ipc *ipc = adev->ipc;
> +	int ret;
> +
> +	if (!ipc->ready)
> +		return -EPERM;
> +
> +	mutex_lock(&ipc->msg_mutex);
> +
> +	spin_lock(&ipc->rx_lock);
> +	avs_ipc_msg_init(ipc, reply);
> +	avs_dsp_send_tx(adev, request);
> +	spin_unlock(&ipc->rx_lock);
> +
> +	ret = avs_ipc_wait_busy_completion(ipc, timeout);
> +	if (ret) {
> +		if (ret == -ETIMEDOUT) {
> +			dev_crit(adev->dev, "communication severed: %d,
> rebooting dsp..\n",
Where does this reboot happen?
Thanks,
Ranjani


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

* Re: [PATCH v3 06/17] ASoC: Intel: avs: Add pipeline management requests
  2022-03-04 14:57 ` [PATCH v3 06/17] ASoC: Intel: avs: Add pipeline management requests Cezary Rojewski
@ 2022-03-04 16:13   ` Ranjani Sridharan
  2022-03-04 17:15     ` Cezary Rojewski
  0 siblings, 1 reply; 65+ messages in thread
From: Ranjani Sridharan @ 2022-03-04 16:13 UTC (permalink / raw)
  To: Cezary Rojewski, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

On Fri, 2022-03-04 at 15:57 +0100, Cezary Rojewski wrote:
> Pipeline represents a scheduling entity. Their existence as well as
> their state machine is controlled through CREATE_PIPELINE,
> DELETE_PIPELINE and SET_PIPELINE_STATE IPCs.
> 
> 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/messages.c | 76
> ++++++++++++++++++++++++++++++++++
>  sound/soc/intel/avs/messages.h | 48 +++++++++++++++++++++
>  2 files changed, 124 insertions(+)
> 
> diff --git a/sound/soc/intel/avs/messages.c
> b/sound/soc/intel/avs/messages.c
> index d568338b0737..de2d50f8c6b4 100644
> --- a/sound/soc/intel/avs/messages.c
> +++ b/sound/soc/intel/avs/messages.c
> @@ -63,3 +63,79 @@ int avs_ipc_load_library(struct avs_dev *adev, u32
> dma_id, u32 lib_id)
>  
>  	return ret;
>  }
> +
> +int avs_ipc_create_pipeline(struct avs_dev *adev, u16 req_size, u8
> priority,
> +			    u8 instance_id, bool lp, u16 attributes)
> +{
> +	union avs_global_msg msg = AVS_GLOBAL_REQUEST(CREATE_PIPELINE);
> +	struct avs_ipc_msg request = {{0}};
> +	int ret;
> +
> +	msg.create_ppl.ppl_mem_size = req_size;
> +	msg.create_ppl.ppl_priority = priority;
> +	msg.create_ppl.instance_id = instance_id;
> +	msg.ext.create_ppl.lp = lp;
> +	msg.ext.create_ppl.attributes = attributes;
> +	request.header = msg.val;
> +
> +	ret = avs_dsp_send_msg(adev, &request, NULL);
> +	if (ret)
> +		avs_ipc_err(adev, &request, "create pipeline", ret);
> +
> +	return ret;
> +}
> +
> +int avs_ipc_delete_pipeline(struct avs_dev *adev, u8 instance_id)
> +{
> +	union avs_global_msg msg = AVS_GLOBAL_REQUEST(DELETE_PIPELINE);
> +	struct avs_ipc_msg request = {{0}};
> +	int ret;
> +
> +	msg.ppl.instance_id = instance_id;
> +	request.header = msg.val;
> +
> +	ret = avs_dsp_send_msg(adev, &request, NULL);
> +	if (ret)
> +		avs_ipc_err(adev, &request, "delete pipeline", ret);
> +
> +	return ret;
> +}
> +
> +int avs_ipc_set_pipeline_state(struct avs_dev *adev, u8 instance_id,
> +			       enum avs_pipeline_state state)
> +{
> +	union avs_global_msg msg =
> AVS_GLOBAL_REQUEST(SET_PIPELINE_STATE);
> +	struct avs_ipc_msg request = {{0}};
> +	int ret;
> +
> +	msg.set_ppl_state.ppl_id = instance_id;
> +	msg.set_ppl_state.state = state;
> +	request.header = msg.val;
> +
> +	ret = avs_dsp_send_msg(adev, &request, NULL);
> +	if (ret)
> +		avs_ipc_err(adev, &request, "set pipeline state", ret);
> +
> +	return ret;
> +}
> +
> +int avs_ipc_get_pipeline_state(struct avs_dev *adev, u8 instance_id,
> +			       enum avs_pipeline_state *state)
Can the pipeline state in the firmware change without the driver's
knowledge? When should the driver use this get_pipeline_state()?

Thanks,Ranjani


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

* Re: [PATCH v3 07/17] ASoC: Intel: avs: Add module management requests
  2022-03-04 14:57 ` [PATCH v3 07/17] ASoC: Intel: avs: Add module " Cezary Rojewski
@ 2022-03-04 16:21   ` Ranjani Sridharan
  2022-03-04 17:21     ` Cezary Rojewski
  0 siblings, 1 reply; 65+ messages in thread
From: Ranjani Sridharan @ 2022-03-04 16:21 UTC (permalink / raw)
  To: Cezary Rojewski, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

On Fri, 2022-03-04 at 15:57 +0100, Cezary Rojewski wrote:
> Firmware modules implement processing algorithms. Their lifecycle,
> similarly to pipelines is being controlled by IPCs: initialization,
> deletion and (un)binding.
> 
> Modules can be configured at runtime - runtime parameters. This is
> done
> with help of LARGE_CONFIG IPCs: getter and setter.
> 
> 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/ipc.c      |   8 +-
>  sound/soc/intel/avs/messages.c | 262
> +++++++++++++++++++++++++++++++++
>  sound/soc/intel/avs/messages.h |  53 +++++++
>  3 files changed, 322 insertions(+), 1 deletion(-)
> 
> diff --git a/sound/soc/intel/avs/ipc.c b/sound/soc/intel/avs/ipc.c
> index c0722f8b195f..9770368a898e 100644
> --- a/sound/soc/intel/avs/ipc.c
> +++ b/sound/soc/intel/avs/ipc.c
> @@ -21,9 +21,15 @@ static void avs_dsp_receive_rx(struct avs_dev
> *adev, u64 header)
>  
>  	ipc->rx.header = header;
>  	/* Abort copying payload if request processing was
> unsuccessful. */
> -	if (!msg.status)
> +	if (!msg.status) {
> +		/* update size in case of LARGE_CONFIG_GET */
> +		if (msg.msg_target == AVS_MOD_MSG &&
> +		    msg.global_msg_type == AVS_MOD_LARGE_CONFIG_GET)
> +			ipc->rx.size =
> msg.ext.large_config.data_off_size;
> +
>  		memcpy_fromio(ipc->rx.data, avs_uplink_addr(adev),
>  			      ipc->rx.size);
> +	}
>  }
>  
>  static void avs_dsp_process_notification(struct avs_dev *adev, u64
> header)
> diff --git a/sound/soc/intel/avs/messages.c
> b/sound/soc/intel/avs/messages.c
> index de2d50f8c6b4..613c9452226d 100644
> --- a/sound/soc/intel/avs/messages.c
> +++ b/sound/soc/intel/avs/messages.c
> @@ -6,6 +6,7 @@
>  //          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
>  //
>  
> +#include <linux/slab.h>
>  #include "avs.h"
>  #include "messages.h"
>  
> @@ -139,3 +140,264 @@ int avs_ipc_get_pipeline_state(struct avs_dev
> *adev, u8 instance_id,
>  	*state = reply.rsp.ext.get_ppl_state.state;
>  	return ret;
>  }
> +
> +/*
> + * avs_ipc_init_instance - Initialize module instance
> + *
> + * @adev: Driver context
> + * @module_id: Module-type id
> + * @instance_id: Unique module instance id
> + * @ppl_id: Parent pipeline id
> + * @core_id: DSP core to allocate module on
> + * @domain: Processing domain (low latency or data processing)
> + * @param: Module-type specific configuration
> + * @param_size: Size of @param in bytes
> + *
> + * Argument verification, as well as pipeline state checks are done
> by the
> + * firmware.
> + *
> + * Note: @ppl_id and @core_id are independent of each other as
> single pipeline
> + * can be composed of module instances located on different DSP
> cores.
> + */
> +int avs_ipc_init_instance(struct avs_dev *adev, u16 module_id, u8
> instance_id,
> +			  u8 ppl_id, u8 core_id, u8 domain,
> +			  void *param, u32 param_size)
> +{
> +	union avs_module_msg msg = AVS_MODULE_REQUEST(INIT_INSTANCE);
> +	struct avs_ipc_msg request;
> +	int ret;
> +
> +	msg.module_id = module_id;
> +	msg.instance_id = instance_id;
> +	/* firmware expects size provided in dwords */
> +	msg.ext.init_instance.param_block_size =
> +			DIV_ROUND_UP(param_size, sizeof(u32));
> +	msg.ext.init_instance.ppl_instance_id = ppl_id;
> +	msg.ext.init_instance.core_id = core_id;
> +	msg.ext.init_instance.proc_domain = domain;
> +
> +	request.header = msg.val;
> +	request.data = param;
> +	request.size = param_size;
> +
> +	ret = avs_dsp_send_msg(adev, &request, NULL);
> +	if (ret)
> +		avs_ipc_err(adev, &request, "init instance", ret);
> +
> +	return ret;
> +}
> +
> +/*
> + * avs_ipc_delete_instance - Delete module instance
> + *
> + * @adev: Driver context
> + * @module_id: Module-type id
> + * @instance_id: Unique module instance id
> + *
> + * Argument verification, as well as pipeline state checks are done
> by the
> + * firmware.
> + *
> + * Note: only standalone modules i.e. without a parent pipeline
> shall be
> + * deleted using this IPC message. In all other cases, pipeline
> owning the
> + * modules peforms cleanup automatically when it is deleted.
Can you please provide an example of such stand-alone modules? If they
aren't part of any pipeline, how do they get scheduled?

> + */
> +int avs_ipc_delete_instance(struct avs_dev *adev, u16 module_id, u8
> instance_id)
> +{
> +	union avs_module_msg msg = AVS_MODULE_REQUEST(DELETE_INSTANCE);
> +	struct avs_ipc_msg request = {{0}};
> +	int ret;
> +
> +	msg.module_id = module_id;
> +	msg.instance_id = instance_id;
> +	request.header = msg.val;
> +
> +	ret = avs_dsp_send_msg(adev, &request, NULL);
> +	if (ret)
> +		avs_ipc_err(adev, &request, "delete instance", ret);
> +
> +	return ret;
> +}
> +
> +/*
> + * avs_ipc_bind - Bind two module instances
> + *
> + * @adev: Driver context
> + * @module_id: Source module-type id
> + * @instance_id: Source module instance id
> + * @dst_module_id: Sink module-type id
> + * @dst_instance_id: Sink module instance id
> + * @dst_queue: Sink module pin to bind @src_queue with
> + * @src_queue: Source module pin to bind @dst_queue with
> + */
> +int avs_ipc_bind(struct avs_dev *adev, u16 module_id, u8
> instance_id,
> +		 u16 dst_module_id, u8 dst_instance_id,
> +		 u8 dst_queue, u8 src_queue)
> +{
> +	union avs_module_msg msg = AVS_MODULE_REQUEST(BIND);
> +	struct avs_ipc_msg request = {{0}};
> +	int ret;
> +
> +	msg.module_id = module_id;
> +	msg.instance_id = instance_id;
> +	msg.ext.bind_unbind.dst_module_id = dst_module_id;
> +	msg.ext.bind_unbind.dst_instance_id = dst_instance_id;
> +	msg.ext.bind_unbind.dst_queue = dst_queue;
> +	msg.ext.bind_unbind.src_queue = src_queue;
> +	request.header = msg.val;
> +
> +	ret = avs_dsp_send_msg(adev, &request, NULL);
> +	if (ret)
> +		avs_ipc_err(adev, &request, "bind modules", ret);
> +
> +	return ret;
> +}
> +
> +/*
> + * avs_ipc_unbind - Unbind two module instances
> + *
> + * @adev: Driver context
> + * @module_id: Source module-type id
> + * @instance_id: Source module instance id
> + * @dst_module_id: Sink module-type id
> + * @dst_instance_id: Sink module instance id
> + * @dst_queue: Sink module pin to unbind @src_queue from
> + * @src_queue: Source module pin to unbind @dst_queue from
> + */
Are there any rules for unbinding? For example if you have 2 modules
connected to a mixer? Can you unbind the module belonging to the host
pipeline that is getting stopped while the mixer is still active?

> +int avs_ipc_unbind(struct avs_dev *adev, u16 module_id, u8
> instance_id,
> +		   u16 dst_module_id, u8 dst_instance_id,
> +		   u8 dst_queue, u8 src_queue)
> +{
> +	union avs_module_msg msg = AVS_MODULE_REQUEST(UNBIND);
> +	struct avs_ipc_msg request = {{0}};
> +	int ret;
> +
> +	msg.module_id = module_id;
> +	msg.instance_id = instance_id;
> +	msg.ext.bind_unbind.dst_module_id = dst_module_id;
> +	msg.ext.bind_unbind.dst_instance_id = dst_instance_id;
> +	msg.ext.bind_unbind.dst_queue = dst_queue;
> +	msg.ext.bind_unbind.src_queue = src_queue;
> +	request.header = msg.val;
> +
> +	ret = avs_dsp_send_msg(adev, &request, NULL);
> +	if (ret)
> +		avs_ipc_err(adev, &request, "unbind modules", ret);
> +
> +	return ret;
> +}
> +
> +static int __avs_ipc_set_large_config(struct avs_dev *adev, u16
> module_id, u8 instance_id,
> +				      u8 param_id, bool init_block,
> bool final_block,
> +				      u8 *request_data, size_t
> request_size, size_t off_size)
> +{
> +	union avs_module_msg msg =
> AVS_MODULE_REQUEST(LARGE_CONFIG_SET);
> +	struct avs_ipc_msg request;
> +	int ret;
> +
> +	msg.module_id = module_id;
> +	msg.instance_id = instance_id;
> +	msg.ext.large_config.data_off_size = off_size;
> +	msg.ext.large_config.large_param_id = param_id;
> +	msg.ext.large_config.final_block = final_block;
> +	msg.ext.large_config.init_block = init_block;
> +
> +	request.header = msg.val;
> +	request.data = request_data;
> +	request.size = request_size;
> +
> +	ret = avs_dsp_send_msg(adev, &request, NULL);
> +	if (ret)
> +		avs_ipc_err(adev, &request, "large config set", ret);
> +
> +	return ret;
> +}
> +
> +int avs_ipc_set_large_config(struct avs_dev *adev, u16 module_id,
> +			     u8 instance_id, u8 param_id,
> +			     u8 *request, size_t request_size)
> +{
> +	size_t remaining, tx_size;
> +	bool final;
> +	int ret;
> +
> +	remaining = request_size;
> +	tx_size = min_t(size_t, AVS_MAILBOX_SIZE, remaining);
> +	final = (tx_size == remaining);
> +
> +	/* Initial request states total payload size. */
> +	ret = __avs_ipc_set_large_config(adev, module_id, instance_id,
> +					 param_id, 1, final, request,
> tx_size,
> +					 request_size);
> +	if (ret)
> +		return ret;
> +
> +	remaining -= tx_size;
> +
> +	/* Loop the rest only when payload exceeds mailbox's size. */
> +	while (remaining) {
> +		size_t offset;
> +
> +		offset = request_size - remaining;
> +		tx_size = min_t(size_t, AVS_MAILBOX_SIZE, remaining);
> +		final = (tx_size == remaining);
> +
> +		ret = __avs_ipc_set_large_config(adev, module_id,
> instance_id,
> +						 param_id, 0, final,
> +						 request + offset,
> tx_size,
> +						 offset);
> +		if (ret)
> +			return ret;
> +
> +		remaining -= tx_size;
> +	}
> +
> +	return 0;
> +}
> +
> +int avs_ipc_get_large_config(struct avs_dev *adev, u16 module_id, u8
> instance_id,
> +			     u8 param_id, u8 *request_data, size_t
> request_size,
> +			     u8 **reply_data, size_t *reply_size)
> +{
> +	union avs_module_msg msg =
> AVS_MODULE_REQUEST(LARGE_CONFIG_GET);
> +	struct avs_ipc_msg request;
> +	struct avs_ipc_msg reply = {{0}};
> +	size_t size;
> +	void *buf;
> +	int ret;
> +
> +	reply.data = kzalloc(AVS_MAILBOX_SIZE, GFP_KERNEL);
> +	if (!reply.data)
> +		return -ENOMEM;
> +
> +	msg.module_id = module_id;
> +	msg.instance_id = instance_id;
> +	msg.ext.large_config.data_off_size = request_size;
> +	msg.ext.large_config.large_param_id = param_id;
> +	/* final_block is always 0 on request. Updated by fw on reply.
> */
> +	msg.ext.large_config.final_block = 0;
> +	msg.ext.large_config.init_block = 1;
> +
> +	request.header = msg.val;
> +	request.data = request_data;
> +	request.size = request_size;
> +	reply.size = AVS_MAILBOX_SIZE;
> +
> +	ret = avs_dsp_send_msg(adev, &request, &reply);
> +	if (ret) {
> +		avs_ipc_err(adev, &request, "large config get", ret);
> +		kfree(reply.data);
> +		return ret;
> +	}
How come you dont have a loop here? What if the rec'd data size if
larger than the max size of IP payload?
Thanks,Ranjani


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

* Re: [PATCH v3 08/17] ASoC: Intel: avs: Add power management requests
  2022-03-04 14:57 ` [PATCH v3 08/17] ASoC: Intel: avs: Add power " Cezary Rojewski
@ 2022-03-04 16:24   ` Ranjani Sridharan
  2022-03-04 17:30     ` Cezary Rojewski
  0 siblings, 1 reply; 65+ messages in thread
From: Ranjani Sridharan @ 2022-03-04 16:24 UTC (permalink / raw)
  To: Cezary Rojewski, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

On Fri, 2022-03-04 at 15:57 +0100, Cezary Rojewski wrote:
> Audio DSP supports low power states i.e.: transitions between D0 and
> D3
> and D0-substates in form of D0i0 and D0i3. That process is a
> combination
> of core and IPC operations. Here, Dx and D0ix IPC handlers are added.
> 
> 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/messages.c | 44
> ++++++++++++++++++++++++++++++++++
>  sound/soc/intel/avs/messages.h | 15 ++++++++++++
>  2 files changed, 59 insertions(+)
> 
> diff --git a/sound/soc/intel/avs/messages.c
> b/sound/soc/intel/avs/messages.c
> index 613c9452226d..e8f441b28d71 100644
> --- a/sound/soc/intel/avs/messages.c
> +++ b/sound/soc/intel/avs/messages.c
> @@ -401,3 +401,47 @@ int avs_ipc_get_large_config(struct avs_dev
> *adev, u16 module_id, u8 instance_id
>  
>  	return 0;
>  }
> +
> +int avs_ipc_set_dx(struct avs_dev *adev, u32 core_mask, bool
> powerup)
a description for this function would be helpful.
> +{
> +	union avs_module_msg msg = AVS_MODULE_REQUEST(SET_DX);
> +	struct avs_ipc_msg request;
> +	struct avs_dxstate_info dx;
> +	int ret;
> +
> +	dx.core_mask = core_mask;
> +	dx.dx_mask = powerup ? core_mask : 0;
> +	request.header = msg.val;
> +	request.data = &dx;
> +	request.size = sizeof(dx);
> +
> +	ret = avs_dsp_send_msg(adev, &request, NULL);
> +	if (ret)
> +		avs_ipc_err(adev, &request, "set dx", ret);
> +
> +	return ret;
> +}
> +
> +/*
> + * avs_ipc_set_d0ix - Set power gating policy (entering D0IX
> substates)
> + *
> + * @enable_pg: Whether to enable or disable power gating
> + * @streaming: Whether a stream is running when transitioning
> + */
What do you mean why "whether a stream is running" does it mean any
stream? What is the difference between a D0ix transition with a stream
running compared to not running?
Thanks,Ranjani


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

* Re: [PATCH v3 09/17] ASoC: Intel: avs: Add ROM requests
  2022-03-04 14:57 ` [PATCH v3 09/17] ASoC: Intel: avs: Add ROM requests Cezary Rojewski
@ 2022-03-04 16:26   ` Ranjani Sridharan
  2022-03-04 17:33     ` Cezary Rojewski
  0 siblings, 1 reply; 65+ messages in thread
From: Ranjani Sridharan @ 2022-03-04 16:26 UTC (permalink / raw)
  To: Cezary Rojewski, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

On Fri, 2022-03-04 at 15:57 +0100, Cezary Rojewski wrote:
> ROM requests are messages initiated by Host to alter firmware early
> boot
> process. They specify whether the next boot should be a fresh start
> or if
> IMR can be used to speed things up.
> 
> 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/messages.c | 18 ++++++++++++++++++
>  sound/soc/intel/avs/messages.h | 14 ++++++++++++++
>  2 files changed, 32 insertions(+)
> 
> diff --git a/sound/soc/intel/avs/messages.c
> b/sound/soc/intel/avs/messages.c
> index e8f441b28d71..f7d00e541323 100644
> --- a/sound/soc/intel/avs/messages.c
> +++ b/sound/soc/intel/avs/messages.c
> @@ -12,6 +12,24 @@
>  
>  #define AVS_CL_TIMEOUT_MS	5000
>  
> +int avs_ipc_set_boot_config(struct avs_dev *adev, u32 dma_id, u32
> purge)
Does purge set to true indicate a fresh boot and a false indicate IMR
restore? A description would help.
Thanks,Ranjani


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

* Re: [PATCH v3 10/17] ASoC: Intel: avs: Add basefw runtime-parameter requests
  2022-03-04 14:57 ` [PATCH v3 10/17] ASoC: Intel: avs: Add basefw runtime-parameter requests Cezary Rojewski
@ 2022-03-04 16:31   ` Ranjani Sridharan
  2022-03-04 17:37     ` Cezary Rojewski
  0 siblings, 1 reply; 65+ messages in thread
From: Ranjani Sridharan @ 2022-03-04 16:31 UTC (permalink / raw)
  To: Cezary Rojewski, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

On Fri, 2022-03-04 at 15:57 +0100, Cezary Rojewski wrote:
> Each module may expose a range of runtime parameters. For basefw,
> implement handlers for: FIRMWARE_CONFIG, HARDWARE_CONFIG and
> MODULES_INFO. These are used by driver to dynamically allocate
> resources
> in respect to platform details, reducing number of hardcodes and code
> duplications that would otherwise be needed to be defined within the
> driver code.
> 
> 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/messages.c | 215
> +++++++++++++++++++++++++++++++++
>  sound/soc/intel/avs/messages.h | 179 +++++++++++++++++++++++++++
>  2 files changed, 394 insertions(+)
> 
> diff --git a/sound/soc/intel/avs/messages.c
> b/sound/soc/intel/avs/messages.c
> index f7d00e541323..7a2a7206df4b 100644
> --- a/sound/soc/intel/avs/messages.c
> +++ b/sound/soc/intel/avs/messages.c
> @@ -463,3 +463,218 @@ int avs_ipc_set_d0ix(struct avs_dev *adev, bool
> enable_pg, bool streaming)
>  
>  	return ret;
>  }
> +
> +int avs_ipc_get_fw_config(struct avs_dev *adev, struct avs_fw_cfg
> *cfg)
> +{
> +	struct avs_tlv *tlv;
> +	size_t payload_size;
> +	size_t offset = 0;
> +	u8 *payload;
> +	int ret;
> +
> +	ret = avs_ipc_get_large_config(adev, AVS_BASEFW_MOD_ID,
> AVS_BASEFW_INST_ID,
> +				       AVS_BASEFW_FIRMWARE_CONFIG,
> NULL, 0,
> +				       &payload, &payload_size);
> +	if (ret)
> +		return ret;
> +
> +	while (offset < payload_size) {
> +		tlv = (struct avs_tlv *)(payload + offset);
> +
> +		switch (tlv->type) {
> +		case AVS_FW_CFG_FW_VERSION:
> +			memcpy(&cfg->fw_version, tlv->value,
> +				sizeof(cfg->fw_version));
> +			break;
> +
> +		case AVS_FW_CFG_MEMORY_RECLAIMED:
> +			cfg->memory_reclaimed = *tlv->value;
> +			break;
> +
> +		case AVS_FW_CFG_SLOW_CLOCK_FREQ_HZ:
> +			cfg->slow_clock_freq_hz = *tlv->value;
> +			break;
> +
> +		case AVS_FW_CFG_FAST_CLOCK_FREQ_HZ:
> +			cfg->fast_clock_freq_hz = *tlv->value;
> +			break;
> +
> +		case AVS_FW_CFG_ALH_SUPPORT_LEVEL:
> +			cfg->alh_support = *tlv->value;
> +			break;
> +
> +		case AVS_FW_CFG_IPC_DL_MAILBOX_BYTES:
> +			cfg->ipc_dl_mailbox_bytes = *tlv->value;
> +			break;
> +
> +		case AVS_FW_CFG_IPC_UL_MAILBOX_BYTES:
> +			cfg->ipc_ul_mailbox_bytes = *tlv->value;
> +			break;
> +
> +		case AVS_FW_CFG_TRACE_LOG_BYTES:
> +			cfg->trace_log_bytes = *tlv->value;
> +			break;
> +
> +		case AVS_FW_CFG_MAX_PPL_COUNT:
> +			cfg->max_ppl_count = *tlv->value;
> +			break;
> +
> +		case AVS_FW_CFG_MAX_ASTATE_COUNT:
> +			cfg->max_astate_count = *tlv->value;
> +			break;
> +
> +		case AVS_FW_CFG_MAX_MODULE_PIN_COUNT:
> +			cfg->max_module_pin_count = *tlv->value;
> +			break;
> +
> +		case AVS_FW_CFG_MODULES_COUNT:
> +			cfg->modules_count = *tlv->value;
> +			break;
> +
> +		case AVS_FW_CFG_MAX_MOD_INST_COUNT:
> +			cfg->max_mod_inst_count = *tlv->value;
> +			break;
> +
> +		case AVS_FW_CFG_MAX_LL_TASKS_PER_PRI_COUNT:
> +			cfg->max_ll_tasks_per_pri_count = *tlv->value;
> +			break;
> +
> +		case AVS_FW_CFG_LL_PRI_COUNT:
> +			cfg->ll_pri_count = *tlv->value;
> +			break;
> +
> +		case AVS_FW_CFG_MAX_DP_TASKS_COUNT:
> +			cfg->max_dp_tasks_count = *tlv->value;
> +			break;
> +
> +		case AVS_FW_CFG_MAX_LIBS_COUNT:
> +			cfg->max_libs_count = *tlv->value;
> +			break;
> +
> +		case AVS_FW_CFG_XTAL_FREQ_HZ:
> +			cfg->xtal_freq_hz = *tlv->value;
> +			break;
> +
> +		case AVS_FW_CFG_POWER_GATING_POLICY:
> +			cfg->power_gating_policy = *tlv->value;
> +			break;
> +
> +		/* Known but not useful to us. */
> +		case AVS_FW_CFG_DMA_BUFFER_CONFIG:
> +		case AVS_FW_CFG_SCHEDULER_CONFIG:
> +		case AVS_FW_CFG_CLOCKS_CONFIG:
> +			break;
> +
> +		default:
> +			dev_info(adev->dev, "Unrecognized fw param:
> %d\n",
> +				 tlv->type);
> +			break;
> +		}
> +
> +		offset += sizeof(*tlv) + tlv->length;
> +	}
> +
> +	kfree(payload);
I think it would be easier to understand this kfree if payload was also
allocated in this function in stead of inside the get_large_config().
Thanks,
Ranjani



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

* Re: [PATCH v3 11/17] ASoC: Intel: avs: Firmware resources management utilities
  2022-03-04 14:57 ` [PATCH v3 11/17] ASoC: Intel: avs: Firmware resources management utilities Cezary Rojewski
@ 2022-03-04 16:41   ` Ranjani Sridharan
  2022-03-04 18:02     ` Cezary Rojewski
  0 siblings, 1 reply; 65+ messages in thread
From: Ranjani Sridharan @ 2022-03-04 16:41 UTC (permalink / raw)
  To: Cezary Rojewski, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

On Fri, 2022-03-04 at 15:57 +0100, Cezary Rojewski wrote:
> With basefw runtime parameter handlers added, implement utility
> functions to ease pipelines and modules allocation. IDA is enlisted
> to
> help with that.
> 
> As firmware is modular and multiple binaries can be loaded on-demand
> depending on the streaming scenario, custom firmware caching
> mechanism
> is added.
> 
> 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    |  37 +++++
>  sound/soc/intel/avs/utils.c  | 301
> +++++++++++++++++++++++++++++++++++
>  3 files changed, 339 insertions(+), 1 deletion(-)
>  create mode 100644 sound/soc/intel/avs/utils.c
> 
> diff --git a/sound/soc/intel/avs/Makefile
> b/sound/soc/intel/avs/Makefile
> index c0824f30fd3b..d9f92c5f5407 100644
> --- a/sound/soc/intel/avs/Makefile
> +++ b/sound/soc/intel/avs/Makefile
> @@ -1,5 +1,5 @@
>  # SPDX-License-Identifier: GPL-2.0-only
>  
> -snd-soc-avs-objs := dsp.o ipc.o messages.o
> +snd-soc-avs-objs := dsp.o ipc.o messages.o utils.o
>  
>  obj-$(CONFIG_SND_SOC_INTEL_AVS) += snd-soc-avs.o
> diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h
> index 841b8541b101..02d7591d0eac 100644
> --- a/sound/soc/intel/avs/avs.h
> +++ b/sound/soc/intel/avs/avs.h
> @@ -53,12 +53,26 @@ struct avs_spec {
>  	const u32 rom_status;
>  };
>  
> +struct avs_fw_entry {
> +	char *name;
> +	const struct firmware *fw;
> +
> +	struct list_head node;
> +};
> +
>  /*
>   * struct avs_dev - Intel HD-Audio driver data
>   *
>   * @dev: PCI device
>   * @dsp_ba: DSP bar address
>   * @spec: platform-specific descriptor
> + * @fw_cfg: Firmware configuration, obtained through FW_CONFIG
> message
> + * @hw_cfg: Hardware configuration, obtained through HW_CONFIG
> message
> + * @mods_info: Available module-types, obtained through MODULES_INFO
> message
> + * @mod_idas: Module instance ID pool, one per module-type
> + * @modres_mutex: For synchronizing any @mods_info updates
Is this mutex really necessary? Can you please elaborate under what
circumstances your will have parallel module updates?

> + * @ppl_ida: Pipeline instance ID pool
> + * @fw_list: List of libraries loaded, including base firmware
>   */
>  struct avs_dev {
>  	struct hda_bus base;
> @@ -68,6 +82,14 @@ struct avs_dev {
>  	const struct avs_spec *spec;
>  	struct avs_ipc *ipc;
>  
> +	struct avs_fw_cfg fw_cfg;
> +	struct avs_hw_cfg hw_cfg;
> +	struct avs_mods_info *mods_info;
> +	struct ida **mod_idas;
> +	struct mutex modres_mutex;
> +	struct ida ppl_ida;
> +	struct list_head fw_list;
> +
>  	struct completion fw_ready;
>  };
>  
> @@ -168,4 +190,19 @@ 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);
>  
> +/* Firmware resources management */
> +
> +int avs_get_module_entry(struct avs_dev *adev, const guid_t *uuid,
> struct avs_module_entry *entry);
> +int avs_get_module_id_entry(struct avs_dev *adev, u32 module_id,
> struct avs_module_entry *entry);
> +int avs_get_module_id(struct avs_dev *adev, const guid_t *uuid);
> +bool avs_is_module_ida_empty(struct avs_dev *adev, u32 module_id);
> +
> +int avs_module_info_init(struct avs_dev *adev, bool purge);
> +void avs_module_info_free(struct avs_dev *adev);
> +int avs_module_id_alloc(struct avs_dev *adev, u16 module_id);
> +void avs_module_id_free(struct avs_dev *adev, u16 module_id, u8
> instance_id);
> +int avs_request_firmware(struct avs_dev *adev, const struct firmware
> **fw_p, const char *name);
> +void avs_release_last_firmware(struct avs_dev *adev);
> +void avs_release_firmwares(struct avs_dev *adev);
> +
>  #endif /* __SOUND_SOC_INTEL_AVS_H */
> diff --git a/sound/soc/intel/avs/utils.c
> b/sound/soc/intel/avs/utils.c
> new file mode 100644
> index 000000000000..580f3e43fa12
> --- /dev/null
> +++ b/sound/soc/intel/avs/utils.c
> @@ -0,0 +1,301 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +//
> +// Copyright(c) 2021 Intel Corporation. All rights reserved.
> +//
> +// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
> +//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
> +//
> +
> +#include <linux/firmware.h>
> +#include <linux/slab.h>
> +#include "avs.h"
> +#include "messages.h"
> +
> +/* Caller responsible for holding adev->modres_mutex. */
> +static int avs_module_entry_index(struct avs_dev *adev, const guid_t
> *uuid)
> +{
> +	int i;
> +
> +	for (i = 0; i < adev->mods_info->count; i++) {
> +		struct avs_module_entry *module;
> +
> +		module = &adev->mods_info->entries[i];
> +		if (guid_equal(&module->uuid, uuid))
> +			return i;
> +	}
> +
> +	return -ENOENT;
> +}
> +
> +/* Caller responsible for holding adev->modres_mutex. */
> +static int avs_module_id_entry_index(struct avs_dev *adev, u32
> module_id)
> +{
> +	int i;
> +
> +	for (i = 0; i < adev->mods_info->count; i++) {
> +		struct avs_module_entry *module;
> +
> +		module = &adev->mods_info->entries[i];
> +		if (module->module_id == module_id)
> +			return i;
> +	}
> +
> +	return -ENOENT;
> +}
> +
> +int avs_get_module_entry(struct avs_dev *adev, const guid_t *uuid,
> struct avs_module_entry *entry)
> +{
> +	int idx;
> +
> +	mutex_lock(&adev->modres_mutex);
> +
> +	idx = avs_module_entry_index(adev, uuid);
> +	if (idx >= 0)
> +		memcpy(entry, &adev->mods_info->entries[idx],
> sizeof(*entry));
> +
> +	mutex_unlock(&adev->modres_mutex);
> +	return (idx < 0) ? idx : 0;
> +}
> +
> +int avs_get_module_id_entry(struct avs_dev *adev, u32 module_id,
> struct avs_module_entry *entry)
> +{
> +	int idx;
> +
> +	mutex_lock(&adev->modres_mutex);
> +
> +	idx = avs_module_id_entry_index(adev, module_id);
> +	if (idx >= 0)
> +		memcpy(entry, &adev->mods_info->entries[idx],
> sizeof(*entry));
> +
> +	mutex_unlock(&adev->modres_mutex);
> +	return (idx < 0) ? idx : 0;
> +}
> +
> +int avs_get_module_id(struct avs_dev *adev, const guid_t *uuid)
> +{
> +	struct avs_module_entry module;
> +	int ret;
> +
> +	ret = avs_get_module_entry(adev, uuid, &module);
> +	return !ret ? module.module_id : -ENOENT;
> +}
> +
> +bool avs_is_module_ida_empty(struct avs_dev *adev, u32 module_id)
> +{
> +	bool ret = false;
> +	int idx;
> +
> +	mutex_lock(&adev->modres_mutex);
> +
> +	idx = avs_module_id_entry_index(adev, module_id);
> +	if (idx >= 0)
> +		ret = ida_is_empty(adev->mod_idas[idx]);
> +
> +	mutex_unlock(&adev->modres_mutex);
> +	return ret;
> +}
> +
> +/* Caller responsible for holding adev->modres_mutex. */
> +static void avs_module_ida_destroy(struct avs_dev *adev)
> +{
> +	int i = adev->mods_info ? adev->mods_info->count : 0;
> +
> +	while (i--) {
> +		ida_destroy(adev->mod_idas[i]);
> +		kfree(adev->mod_idas[i]);
> +	}
> +	kfree(adev->mod_idas);
> +}
> +
> +/* Caller responsible for holding adev->modres_mutex. */
> +static int
> +avs_module_ida_alloc(struct avs_dev *adev, struct avs_mods_info
> *newinfo, bool purge)
> +{
> +	struct avs_mods_info *oldinfo = adev->mods_info;
> +	struct ida **ida_ptrs;
> +	u32 tocopy_count = 0;
> +	int i;
> +
> +	if (!purge && oldinfo) {
> +		if (oldinfo->count >= newinfo->count)
> +			dev_warn(adev->dev, "refreshing %d modules info
> with %d\n",
> +				 oldinfo->count, newinfo->count);
> +		tocopy_count = oldinfo->count;
> +	}
> +
> +	ida_ptrs = kcalloc(newinfo->count, sizeof(*ida_ptrs),
> GFP_KERNEL);
> +	if (!ida_ptrs)
> +		return -ENOMEM;
> +
> +	if (tocopy_count)
> +		memcpy(ida_ptrs, adev->mod_idas, tocopy_count *
> sizeof(*ida_ptrs));
> +
> +	for (i = tocopy_count; i < newinfo->count; i++) {
> +		ida_ptrs[i] = kzalloc(sizeof(**ida_ptrs), GFP_KERNEL);
> +		if (!ida_ptrs[i]) {
> +			while (i--)
> +				kfree(ida_ptrs[i]);
> +
> +			kfree(ida_ptrs);
> +			return -ENOMEM;
> +		}
> +
> +		ida_init(ida_ptrs[i]);
> +	}
> +
> +	/* If old elements have been reused, don't wipe them. */
> +	if (tocopy_count)
> +		kfree(adev->mod_idas);
> +	else
> +		avs_module_ida_destroy(adev);
> +
> +	adev->mod_idas = ida_ptrs;
> +	return 0;
> +}
> +
> +int avs_module_info_init(struct avs_dev *adev, bool purge)
> +{
> +	struct avs_mods_info *info;
> +	int ret;
> +
> +	ret = avs_ipc_get_modules_info(adev, &info);
> +	if (ret)
> +		return AVS_IPC_RET(ret);
> +
> +	mutex_lock(&adev->modres_mutex);
> +
> +	ret = avs_module_ida_alloc(adev, info, purge);
> +	if (ret < 0) {
> +		dev_err(adev->dev, "initialize module idas failed:
> %d\n", ret);
> +		goto exit;
> +	}
> +
> +	/* Refresh current information with newly received table. */
> +	kfree(adev->mods_info);
> +	adev->mods_info = info;
> +
> +exit:
> +	mutex_unlock(&adev->modres_mutex);
> +	return ret;
> +}
> +
> +void avs_module_info_free(struct avs_dev *adev)
> +{
> +	mutex_lock(&adev->modres_mutex);
> +
> +	avs_module_ida_destroy(adev);
> +	kfree(adev->mods_info);
> +	adev->mods_info = NULL;
> +
> +	mutex_unlock(&adev->modres_mutex);
> +}
> +
> +int avs_module_id_alloc(struct avs_dev *adev, u16 module_id)
> +{
> +	int ret, idx, max_id;
> +
> +	mutex_lock(&adev->modres_mutex);
> +
> +	idx = avs_module_id_entry_index(adev, module_id);
> +	if (idx == -ENOENT) {
Can you please help me understand when this can happen? If all modules
required by the topology are already initialized, will this ever
happen?
Thanks,
Ranjani


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

* Re: [PATCH v3 12/17] ASoC: Intel: avs: Declare module configuration types
  2022-03-04 14:57 ` [PATCH v3 12/17] ASoC: Intel: avs: Declare module configuration types Cezary Rojewski
@ 2022-03-04 16:43   ` Ranjani Sridharan
  2022-03-04 18:10     ` Cezary Rojewski
  0 siblings, 1 reply; 65+ messages in thread
From: Ranjani Sridharan @ 2022-03-04 16:43 UTC (permalink / raw)
  To: Cezary Rojewski, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

On Fri, 2022-03-04 at 15:57 +0100, Cezary Rojewski wrote:
> Declare structures and constants for all modules being part of basefw
> binary. These are used in streaming operations to communicate the
> needs
> of software to firmware side.
> 
> While adding module types, append handler for SET_SINK_FORMAT runtime
> for COPIER module which allows for configuration of output pin other
> than the default one (0).
> 
> 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/messages.c |  17 +++
>  sound/soc/intel/avs/messages.h | 252
> +++++++++++++++++++++++++++++++++
>  2 files changed, 269 insertions(+)
> 
> diff --git a/sound/soc/intel/avs/messages.c
> b/sound/soc/intel/avs/messages.c
> index 7a2a7206df4b..44566705e56c 100644
> --- a/sound/soc/intel/avs/messages.c
> +++ b/sound/soc/intel/avs/messages.c
> @@ -678,3 +678,20 @@ int avs_ipc_get_modules_info(struct avs_dev
> *adev, struct avs_mods_info **info)
>  	*info = (struct avs_mods_info *)payload;
>  	return 0;
>  }
> +
> +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,
> +				   const struct avs_audio_format
> *sink_fmt)
> +{
> +	struct avs_copier_sink_format cpr_fmt;
> +
> +	cpr_fmt.sink_id = sink_id;
> +	/* Firmware expects driver to resend copier's input format. */
> +	cpr_fmt.src_fmt = *src_fmt;
> +	cpr_fmt.sink_fmt = *sink_fmt;
> +
> +	return avs_ipc_set_large_config(adev, module_id, instance_id,
> +					AVS_COPIER_SET_SINK_FORMAT,
> +					(u8 *)&cpr_fmt,
> sizeof(cpr_fmt));
> +}
> diff --git a/sound/soc/intel/avs/messages.h
> b/sound/soc/intel/avs/messages.h
> index 67ba0a6347a1..966139e9663d 100644
> --- a/sound/soc/intel/avs/messages.h
> +++ b/sound/soc/intel/avs/messages.h
> @@ -498,4 +498,256 @@ 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);
>  
> +/* Module configuration */
> +
> +#define AVS_MIXIN_MOD_UUID \
> +	GUID_INIT(0x39656EB2, 0x3B71, 0x4049, 0x8D, 0x3F, 0xF9, 0x2C,
> 0xD5, 0xC4, 0x3C, 0x09)
> +
> +#define AVS_MIXOUT_MOD_UUID \
> +	GUID_INIT(0x3C56505A, 0x24D7, 0x418F, 0xBD, 0xDC, 0xC1, 0xF5,
> 0xA3, 0xAC, 0x2A, 0xE0)
> +
> +#define AVS_COPIER_MOD_UUID \
> +	GUID_INIT(0x9BA00C83, 0xCA12, 0x4A83, 0x94, 0x3C, 0x1F, 0xA2,
> 0xE8, 0x2F, 0x9D, 0xDA)
> +
> +#define AVS_KPBUFF_MOD_UUID \
> +	GUID_INIT(0xA8A0CB32, 0x4A77, 0x4DB1, 0x85, 0xC7, 0x53, 0xD7,
> 0xEE, 0x07, 0xBC, 0xE6)
> +
> +#define AVS_MICSEL_MOD_UUID \
> +	GUID_INIT(0x32FE92C1, 0x1E17, 0x4FC2, 0x97, 0x58, 0xC7, 0xF3,
> 0x54, 0x2E, 0x98, 0x0A)
> +
> +#define AVS_MUX_MOD_UUID \
> +	GUID_INIT(0x64CE6E35, 0x857A, 0x4878, 0xAC, 0xE8, 0xE2, 0xA2,
> 0xF4, 0x2e, 0x30, 0x69)
> +
> +#define AVS_UPDWMIX_MOD_UUID \
> +	GUID_INIT(0x42F8060C, 0x832F, 0x4DBF, 0xB2, 0x47, 0x51, 0xE9,
> 0x61, 0x99, 0x7b, 0x35)
> +
> +#define AVS_SRCINTC_MOD_UUID \
> +	GUID_INIT(0xE61BB28D, 0x149A, 0x4C1F, 0xB7, 0x09, 0x46, 0x82,
> 0x3E, 0xF5, 0xF5, 0xAE)
> +
> +#define AVS_PROBE_MOD_UUID \
> +	GUID_INIT(0x7CAD0808, 0xAB10, 0xCD23, 0xEF, 0x45, 0x12, 0xAB,
> 0x34, 0xCD, 0x56, 0xEF)
> +
> +#define AVS_AEC_MOD_UUID \
> +	GUID_INIT(0x46CB87FB, 0xD2C9, 0x4970, 0x96, 0xD2, 0x6D, 0x7E,
> 0x61, 0x4B, 0xB6, 0x05)
> +
> +#define AVS_ASRC_MOD_UUID \
> +	GUID_INIT(0x66B4402D, 0xB468, 0x42F2, 0x81, 0xA7, 0xB3, 0x71,
> 0x21, 0x86, 0x3D, 0xD4)
> +
> +#define AVS_INTELWOV_MOD_UUID \
> +	GUID_INIT(0xEC774FA9, 0x28D3, 0x424A, 0x90, 0xE4, 0x69, 0xF9,
> 0x84, 0xF1, 0xEE, 0xB7)
Why do you need to hard-code this? DOes the fw config info that you
retrieve using get_large_config or even the FW manifest have it
already?
Thanks,Ranjani


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

* Re: [PATCH v3 03/17] ASoC: Intel: Introduce AVS driver
  2022-03-04 15:51   ` Ranjani Sridharan
@ 2022-03-04 16:43     ` Cezary Rojewski
  0 siblings, 0 replies; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-04 16:43 UTC (permalink / raw)
  To: Ranjani Sridharan, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

On 2022-03-04 4:51 PM, Ranjani Sridharan wrote:

...

>> +#ifndef __SOUND_SOC_INTEL_AVS_H
>> +#define __SOUND_SOC_INTEL_AVS_H
>> +
>> +#include <linux/device.h>
>> +#include <sound/hda_codec.h>
>> +
>> +struct avs_dev;
>> +
>> +struct avs_dsp_ops {
>> +	int (* const power)(struct avs_dev *, u32, bool);
>> +	int (* const reset)(struct avs_dev *, u32, bool);
>> +	int (* const stall)(struct avs_dev *, u32, bool);
>> +};
>> +
>> +#define avs_dsp_op(adev, op, ...) \
>> +	((adev)->spec->dsp_ops->op(adev, ## __VA_ARGS__))
>> +
>> +#define avs_platattr_test(adev, attr) \
>> +	((adev)->spec->attributes & AVS_PLATATTR_##attr)
> AVS_PLATATTR_* don't seem to be defined in this patch?
> 
> Thanks,
> Ranjani
> 

Thanks for feedback! Consider dropping the unnecessary bits so it is 
easier to navigate through your responses.

Yes, AVS_PLATATTR_ constants were split from this patch. This patch 
defines just base API instead.


Regards,
Czarek

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

* Re: [PATCH v3 13/17] ASoC: Intel: avs: Dynamic firmware resources management
  2022-03-04 14:57 ` [PATCH v3 13/17] ASoC: Intel: avs: Dynamic firmware resources management Cezary Rojewski
@ 2022-03-04 16:47   ` Ranjani Sridharan
  2022-03-04 18:15     ` Cezary Rojewski
  0 siblings, 1 reply; 65+ messages in thread
From: Ranjani Sridharan @ 2022-03-04 16:47 UTC (permalink / raw)
  To: Cezary Rojewski, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

On Fri, 2022-03-04 at 15:57 +0100, Cezary Rojewski wrote:
> Wrap elementary DSP-core operations and resource control into more
> complex handlers. This is done to reduce the number of invocations of
> wrapped operations throughout the driver as order of operations
> matters -
> most flows involve register manipulation and IPCs combined.
> 
> 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 |  10 +++
>  sound/soc/intel/avs/dsp.c | 170
> ++++++++++++++++++++++++++++++++++++++
>  2 files changed, 180 insertions(+)
> 
> diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h
> index 02d7591d0eac..0034c075fa64 100644
> --- a/sound/soc/intel/avs/avs.h
> +++ b/sound/soc/intel/avs/avs.h
> @@ -89,6 +89,7 @@ struct avs_dev {
>  	struct mutex modres_mutex;
>  	struct ida ppl_ida;
>  	struct list_head fw_list;
> +	int *core_refs;

Is this a per core ref_count? a comment or explicitly calling it
core_ref_count would help.

Thanks,Ranjani


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

* Re: [PATCH v3 14/17] ASoC: Intel: avs: General code loading flow
  2022-03-04 14:57 ` [PATCH v3 14/17] ASoC: Intel: avs: General code loading flow Cezary Rojewski
@ 2022-03-04 16:54   ` Ranjani Sridharan
  2022-03-04 18:29     ` Cezary Rojewski
  0 siblings, 1 reply; 65+ messages in thread
From: Ranjani Sridharan @ 2022-03-04 16:54 UTC (permalink / raw)
  To: Cezary Rojewski, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

On Fri, 2022-03-04 at 15:57 +0100, Cezary Rojewski wrote:
> Code loading is a complex procedure and requires combined effort of
> DMA
> and IPCs. With IPCs already in place, lay out ground for specific DMA
> transfer operations.
> 
> 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       |  18 +++
>  sound/soc/intel/avs/core.c      |  62 +++++++++
>  sound/soc/intel/avs/dsp.c       |  26 ++++
>  sound/soc/intel/avs/loader.c    | 237
> ++++++++++++++++++++++++++++++++
>  sound/soc/intel/avs/registers.h |   6 +
>  6 files changed, 350 insertions(+), 1 deletion(-)
>  create mode 100644 sound/soc/intel/avs/core.c
>  create mode 100644 sound/soc/intel/avs/loader.c
> 
> diff --git a/sound/soc/intel/avs/Makefile
> b/sound/soc/intel/avs/Makefile
> index d9f92c5f5407..d9c793160612 100644
> --- a/sound/soc/intel/avs/Makefile
> +++ b/sound/soc/intel/avs/Makefile
> @@ -1,5 +1,5 @@
>  # SPDX-License-Identifier: GPL-2.0-only
>  
> -snd-soc-avs-objs := dsp.o ipc.o messages.o utils.o
> +snd-soc-avs-objs := dsp.o ipc.o messages.o utils.o core.o loader.o
>  
>  obj-$(CONFIG_SND_SOC_INTEL_AVS) += snd-soc-avs.o
> diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h
> index 0034c075fa64..2527d6170417 100644
> --- a/sound/soc/intel/avs/avs.h
> +++ b/sound/soc/intel/avs/avs.h
> @@ -10,8 +10,11 @@
>  #define __SOUND_SOC_INTEL_AVS_H
>  
>  #include <linux/device.h>
> +#include <linux/firmware.h>
>  #include <sound/hda_codec.h>
> +#include <sound/hda_register.h>
>  #include "messages.h"
> +#include "registers.h"
>  
>  struct avs_dev;
>  
> @@ -32,6 +35,10 @@ struct avs_dsp_ops {
>  	irqreturn_t (* const irq_handler)(int, void *);
>  	irqreturn_t (* const irq_thread)(int, void *);
>  	void (* const int_control)(struct avs_dev *, bool);
> +	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);
>  };
>  
>  #define avs_dsp_op(adev, op, ...) \
> @@ -45,6 +52,7 @@ struct avs_spec {
>  	const char *name;
>  
>  	const struct avs_dsp_ops *const dsp_ops;
> +	struct avs_fw_version min_fw_version; /* anything below is
> rejected */
>  
>  	const u32 core_init_mask;	/* used during DSP boot */
>  	const u64 attributes;		/* bitmask of AVS_PLATATTR_*
> */
> @@ -90,6 +98,7 @@ struct avs_dev {
>  	struct ida ppl_ida;
>  	struct list_head fw_list;
>  	int *core_refs;
> +	char **lib_names;
>  
>  	struct completion fw_ready;
>  };
> @@ -215,4 +224,13 @@ int avs_dsp_create_pipeline(struct avs_dev
> *adev, u16 req_size, u8 priority,
>  			    bool lp, u16 attributes, u8 *instance_id);
>  int avs_dsp_delete_pipeline(struct avs_dev *adev, u8 instance_id);
>  
> +/* Firmware loading */
> +
> +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_boot_firmware(struct avs_dev *adev, bool purge);
> +int avs_dsp_first_boot_firmware(struct avs_dev *adev);
> +
>  #endif /* __SOUND_SOC_INTEL_AVS_H */
> diff --git a/sound/soc/intel/avs/core.c b/sound/soc/intel/avs/core.c
> new file mode 100644
> index 000000000000..117b31ef9cd0
> --- /dev/null
> +++ b/sound/soc/intel/avs/core.c
> @@ -0,0 +1,62 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +//
> +// Copyright(c) 2021 Intel Corporation. All rights reserved.
> +//
> +// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
> +//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
> +//
> +// Special thanks to:
> +//    Krzysztof Hejmowski <krzysztof.hejmowski@intel.com>
> +//    Michal Sienkiewicz <michal.sienkiewicz@intel.com>
> +//    Filip Proborszcz
> +//
> +// for sharing Intel AudioDSP expertise and helping shape the very
> +// foundation of this driver
> +//
> +
> +#include <linux/pci.h>
> +#include <sound/hdaudio.h>
> +#include "avs.h"
> +
> +static void
> +avs_hda_update_config_dword(struct hdac_bus *bus, u32 reg, u32 mask,
> u32 value)
> +{
> +	struct pci_dev *pci = to_pci_dev(bus->dev);
> +	u32 data;
> +
> +	pci_read_config_dword(pci, reg, &data);
> +	data &= ~mask;
> +	data |= (value & mask);
> +	pci_write_config_dword(pci, reg, data);
> +}
> +
> +void avs_hda_power_gating_enable(struct avs_dev *adev, bool enable)
> +{
> +	u32 value;
> +
> +	value = enable ? 0 : AZX_PGCTL_LSRMD_MASK;
> +	avs_hda_update_config_dword(&adev->base.core, AZX_PCIREG_PGCTL,
> +				    AZX_PGCTL_LSRMD_MASK, value);
> +}
> +
> +static void avs_hdac_clock_gating_enable(struct hdac_bus *bus, bool
> enable)
> +{
> +	u32 value;
> +
> +	value = enable ? AZX_CGCTL_MISCBDCGE_MASK : 0;
> +	avs_hda_update_config_dword(bus, AZX_PCIREG_CGCTL,
> +				    AZX_CGCTL_MISCBDCGE_MASK, value);
> +}
> +
> +void avs_hda_clock_gating_enable(struct avs_dev *adev, bool enable)
> +{
> +	avs_hdac_clock_gating_enable(&adev->base.core, enable);
> +}
> +
> +void avs_hda_l1sen_enable(struct avs_dev *adev, bool enable)
> +{
> +	u32 value;
> +
> +	value = enable ? AZX_VS_EM2_L1SEN : 0;
> +	snd_hdac_chip_updatel(&adev->base.core, VS_EM2,
> AZX_VS_EM2_L1SEN, value);
> +}
> diff --git a/sound/soc/intel/avs/dsp.c b/sound/soc/intel/avs/dsp.c
> index 5994d64d2468..a434e9918c51 100644
> --- a/sound/soc/intel/avs/dsp.c
> +++ b/sound/soc/intel/avs/dsp.c
> @@ -198,6 +198,7 @@ int avs_dsp_init_module(struct avs_dev *adev, u16
> module_id, u8 ppl_instance_id,
>  			u16 *instance_id)
>  {
>  	struct avs_module_entry mentry;
> +	bool was_loaded = false;
>  	int ret, id;
>  
>  	id = avs_module_id_alloc(adev, module_id);
> @@ -212,6 +213,16 @@ int avs_dsp_init_module(struct avs_dev *adev,
> u16 module_id, u8 ppl_instance_id,
>  	if (ret)
>  		goto err_mod_entry;
>  
> +	/* Load code into memory if this is the first instance. */
> +	if (!id && !avs_module_entry_is_loaded(&mentry)) {
> +		ret = avs_dsp_op(adev, transfer_mods, true, &mentry,
> 1);
> +		if (ret) {
> +			dev_err(adev->dev, "load modules failed: %d\n",
> ret);
> +			goto err_mod_entry;
> +		}
> +		was_loaded = true;
> +	}
> +
>  	ret = avs_ipc_init_instance(adev, module_id, id,
> ppl_instance_id,
>  				    core_id, domain, param,
> param_size);
>  	if (ret) {
> @@ -223,6 +234,8 @@ int avs_dsp_init_module(struct avs_dev *adev, u16
> module_id, u8 ppl_instance_id,
>  	return 0;
>  
>  err_ipc:
> +	if (was_loaded)
> +		avs_dsp_op(adev, transfer_mods, false, &mentry, 1);
>  	avs_dsp_put_core(adev, core_id);
>  err_mod_entry:
>  	avs_module_id_free(adev, module_id, id);
> @@ -232,12 +245,25 @@ int avs_dsp_init_module(struct avs_dev *adev,
> u16 module_id, u8 ppl_instance_id,
>  void avs_dsp_delete_module(struct avs_dev *adev, u16 module_id, u16
> instance_id,
>  			   u8 ppl_instance_id, u8 core_id)
>  {
> +	struct avs_module_entry mentry;
> +	int ret;
> +
>  	/* Modules not owned by any pipeline need to be freed
> explicitly. */
>  	if (ppl_instance_id == INVALID_PIPELINE_ID)
>  		avs_ipc_delete_instance(adev, module_id, instance_id);
>  
>  	avs_module_id_free(adev, module_id, instance_id);
>  
> +	ret = avs_get_module_id_entry(adev, module_id, &mentry);
> +	/* Unload occupied memory if this was the last instance. */
> +	if (!ret && mentry.type.load_type ==
> AVS_MODULE_LOAD_TYPE_LOADABLE) {
> +		if (avs_is_module_ida_empty(adev, module_id)) {
> +			ret = avs_dsp_op(adev, transfer_mods, false,
> &mentry, 1);
> +			if (ret)
> +				dev_err(adev->dev, "unload modules
> failed: %d\n", ret);
> +		}
> +	}
> +
>  	avs_dsp_put_core(adev, core_id);
>  }
>  
> diff --git a/sound/soc/intel/avs/loader.c
> b/sound/soc/intel/avs/loader.c
> new file mode 100644
> index 000000000000..47e1f9a21e43
> --- /dev/null
> +++ b/sound/soc/intel/avs/loader.c
> @@ -0,0 +1,237 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +//
> +// Copyright(c) 2021 Intel Corporation. All rights reserved.
> +//
> +// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
> +//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
> +//
> +
> +#include <linux/firmware.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include "avs.h"
> +#include "messages.h"
> +#include "registers.h"
> +
> +#define AVS_FW_INIT_TIMEOUT_MS		3000
> +
> +#define AVS_ROOT_DIR			"intel/avs"
> +#define AVS_BASEFW_FILENAME		"dsp_basefw.bin"
> +#define AVS_EXT_MANIFEST_MAGIC		0x31454124
> +#define SKL_MANIFEST_MAGIC		0x00000006
> +#define SKL_ADSPFW_OFFSET		0x284
> +
> +/* Occasionally, engineering (release candidate) firmware is
> provided for testing. */
> +static bool debug_ignore_fw_version;
> +module_param_named(ignore_fw_version, debug_ignore_fw_version, bool,
> 0444);
> +MODULE_PARM_DESC(ignore_fw_version, "Verify FW version 0=yes
> (default), 1=no");
> +
> +#define AVS_LIB_NAME_SIZE	8
> +
> +struct avs_fw_manifest {
> +	u32 id;
> +	u32 len;
> +	char name[AVS_LIB_NAME_SIZE];
> +	u32 preload_page_count;
> +	u32 img_flags;
> +	u32 feature_mask;
> +	struct avs_fw_version version;
> +} __packed;
> +
> +struct avs_fw_ext_manifest {
> +	u32 id;
> +	u32 len;
> +	u16 version_major;
> +	u16 version_minor;
> +	u32 entries;
> +} __packed;
> +
> +static int avs_fw_ext_manifest_strip(struct firmware *fw)
> +{
> +	struct avs_fw_ext_manifest *man;
> +
> +	if (fw->size < sizeof(*man))
> +		return -EINVAL;
> +
> +	man = (struct avs_fw_ext_manifest *)fw->data;
> +	if (man->id == AVS_EXT_MANIFEST_MAGIC) {
> +		fw->data += man->len;
> +		fw->size -= man->len;
> +	}
> +
> +	return 0;
> +}
> +
> +static int avs_fw_manifest_offset(struct firmware *fw)
> +{
> +	/* Header type found in first DWORD of fw binary. */
> +	u32 magic = *(u32 *)fw->data;
> +
> +	switch (magic) {
> +	case SKL_MANIFEST_MAGIC:
> +		return SKL_ADSPFW_OFFSET;
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static int avs_fw_manifest_strip_verify(struct avs_dev *adev, struct
> firmware *fw,
> +					const struct avs_fw_version
> *min)
> +{
> +	struct avs_fw_manifest *man;
> +	int offset, ret;
> +
> +	ret = avs_fw_ext_manifest_strip(fw);
> +	if (ret)
> +		return ret;
> +
> +	offset = avs_fw_manifest_offset(fw);
> +	if (offset < 0)
> +		return offset;
> +
> +	if (fw->size < offset + sizeof(*man))
> +		return -EINVAL;
> +	if (!min)
> +		return 0;
> +
> +	man = (struct avs_fw_manifest *)(fw->data + offset);
> +	if (man->version.major != min->major ||
> +	    man->version.minor != min->minor ||
> +	    man->version.hotfix != min->hotfix ||
> +	    man->version.build < min->build) {
Isnt this check a bit too strict? Isnt a check major enough?

> +		dev_warn(adev->dev, "bad FW version %d.%d.%d.%d,
> expected %d.%d.%d.%d or newer\n",
> +			 man->version.major, man->version.minor,
> +			 man->version.hotfix, man->version.build,
> +			 min->major, min->minor, min->hotfix, min-
> >build);
> +
> +		if (!debug_ignore_fw_version)
> +			return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static int avs_dsp_load_basefw(struct avs_dev *adev)
> +{
> +	const struct avs_fw_version *min_req;
> +	const struct avs_spec *const spec = adev->spec;
> +	const struct firmware *fw;
> +	struct firmware stripped_fw;
> +	char *filename;
> +	int ret;
> +
> +	filename = kasprintf(GFP_KERNEL, "%s/%s/%s", AVS_ROOT_DIR,
> spec->name,
> +			     AVS_BASEFW_FILENAME);
> +	if (!filename)
> +		return -ENOMEM;
> +
> +	ret = avs_request_firmware(adev, &fw, filename);
> +	kfree(filename);
> +	if (ret < 0) {
> +		dev_err(adev->dev, "request firmware failed: %d\n",
> ret);
> +		return ret;
> +	}
> +
> +	stripped_fw = *fw;
> +	min_req = &adev->spec->min_fw_version;
> +
> +	ret = avs_fw_manifest_strip_verify(adev, &stripped_fw,
> min_req);
> +	if (ret < 0) {
> +		dev_err(adev->dev, "invalid firmware data: %d\n", ret);
> +		goto release_fw;
> +	}
> +
> +	ret = avs_dsp_op(adev, load_basefw, &stripped_fw);
> +	if (ret < 0) {
> +		dev_err(adev->dev, "basefw load failed: %d\n", ret);
> +		goto release_fw;
> +	}
> +
> +	ret = wait_for_completion_timeout(&adev->fw_ready,
> +					  msecs_to_jiffies(AVS_FW_INIT_
> TIMEOUT_MS));
> +	if (!ret) {
> +		dev_err(adev->dev, "firmware ready timeout\n");
> +		avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK);
> +		ret = -ETIMEDOUT;
> +		goto release_fw;
> +	}
> +
> +	return 0;
> +
> +release_fw:
> +	avs_release_last_firmware(adev);
> +	return ret;
> +}
> +
> +int avs_dsp_boot_firmware(struct avs_dev *adev, bool purge)
> +{
> +	int ret, i;
> +
> +	/* Full boot, clear cached data except for basefw (slot 0). */
Does this mean IMR restore is only available for base FW and not for
module libraries? Do I understand this correctly?
> +	for (i = 1; i < adev->fw_cfg.max_libs_count; i++)
> +		memset(adev->lib_names[i], 0, AVS_LIB_NAME_SIZE);
> +
> +	avs_hda_clock_gating_enable(adev, false);
> +	avs_hda_l1sen_enable(adev, false);
> +
> +	ret = avs_dsp_load_basefw(adev);
> +
> +	avs_hda_l1sen_enable(adev, true);
> +	avs_hda_clock_gating_enable(adev, true);
> +
> +	if (ret < 0)
> +		return ret;
> +
> +	/* With all code loaded, refresh module information. */
> +	ret = avs_module_info_init(adev, true);
It is not clear if this required only after first boot or after a
suspend/resume as well.
Thanks,Ranjani


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

* Re: [PATCH v3 17/17] ASoC: Intel: avs: Code loading over HDA
  2022-03-04 14:57 ` [PATCH v3 17/17] ASoC: Intel: avs: Code loading over HDA Cezary Rojewski
@ 2022-03-04 16:59   ` Ranjani Sridharan
  2022-03-04 18:44     ` Cezary Rojewski
  0 siblings, 1 reply; 65+ messages in thread
From: Ranjani Sridharan @ 2022-03-04 16:59 UTC (permalink / raw)
  To: Cezary Rojewski, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

On Fri, 2022-03-04 at 15:57 +0100, Cezary Rojewski wrote:
> Compared to SKL and KBL, younger cAVS platforms are meant to re-use
> one
Younger? you mean newer?
> of HDAudio streams during boot procedure causing CLDMA to become
> obsolete. Once transferred, given stream is returned to pool
> available
> for audio streaming.
> 
> Module loading handler is dummy as library and module code became
> inseparable in later firmware generations.
replace dummy with "stub" maybe? lets use inclusive terms
> 
> 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    |   5 +
>  sound/soc/intel/avs/loader.c | 211
> +++++++++++++++++++++++++++++++++++
>  3 files changed, 217 insertions(+)
> 
> diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
> index e9768c4aa1a9..d025ca0c77fa 100644
> --- a/sound/soc/intel/Kconfig
> +++ b/sound/soc/intel/Kconfig
> @@ -215,6 +215,7 @@ config SND_SOC_INTEL_AVS
>  	depends on COMMON_CLK
>  	select SND_SOC_ACPI
>  	select SND_HDA_EXT_CORE
> +	select SND_HDA_DSP_LOADER
>  	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 fb3520f32488..6dc5d17ccf21 100644
> --- a/sound/soc/intel/avs/avs.h
> +++ b/sound/soc/intel/avs/avs.h
> @@ -45,6 +45,7 @@ struct avs_dsp_ops {
>  	((adev)->spec->dsp_ops->op(adev, ## __VA_ARGS__))
>  
>  #define AVS_PLATATTR_CLDMA		BIT_ULL(0)
> +#define AVS_PLATATTR_IMR		BIT_ULL(1)
>  
>  #define avs_platattr_test(adev, attr) \
>  	((adev)->spec->attributes & AVS_PLATATTR_##attr)
> @@ -239,5 +240,9 @@ int avs_cldma_load_basefw(struct avs_dev *adev,
> struct firmware *fw);
>  int avs_cldma_load_library(struct avs_dev *adev, struct firmware
> *lib, u32 id);
>  int avs_cldma_transfer_modules(struct avs_dev *adev, bool load,
>  			       struct avs_module_entry *mods, u32
> num_mods);
> +int avs_hda_load_basefw(struct avs_dev *adev, struct firmware *fw);
> +int avs_hda_load_library(struct avs_dev *adev, struct firmware *lib,
> u32 id);
> +int avs_hda_transfer_modules(struct avs_dev *adev, bool load,
> +			     struct avs_module_entry *mods, u32
> num_mods);
>  
>  #endif /* __SOUND_SOC_INTEL_AVS_H */
> diff --git a/sound/soc/intel/avs/loader.c
> b/sound/soc/intel/avs/loader.c
> index 2134aaabe2c6..6520f23fc70e 100644
> --- a/sound/soc/intel/avs/loader.c
> +++ b/sound/soc/intel/avs/loader.c
> @@ -9,6 +9,7 @@
>  #include <linux/firmware.h>
>  #include <linux/module.h>
>  #include <linux/slab.h>
> +#include <sound/hdaudio.h>
>  #include <sound/hdaudio_ext.h>
>  #include "avs.h"
>  #include "cldma.h"
> @@ -18,8 +19,11 @@
>  #define AVS_ROM_STS_MASK		0xFF
>  #define AVS_ROM_INIT_DONE		0x1
>  #define SKL_ROM_BASEFW_ENTERED		0xF
> +#define APL_ROM_FW_ENTERED		0x5
>  #define AVS_ROM_INIT_POLLING_US		5
>  #define SKL_ROM_INIT_TIMEOUT_US		1000000
> +#define APL_ROM_INIT_TIMEOUT_US		300000
> +#define APL_ROM_INIT_RETRIES		3
>  
>  #define AVS_FW_INIT_POLLING_US		500
>  #define AVS_FW_INIT_TIMEOUT_US		3000000
> @@ -261,6 +265,204 @@ int avs_cldma_transfer_modules(struct avs_dev
> *adev, bool load,
>  	return 0;
>  }
>  
> +static int
> +avs_hda_init_rom(struct avs_dev *adev, unsigned int dma_id, bool
> purge)
> +{
> +	const struct avs_spec *const spec = adev->spec;
> +	unsigned int corex_mask, reg;
> +	int ret;
> +
> +	corex_mask = spec->core_init_mask & ~AVS_MAIN_CORE_MASK;
> +
> +	ret = avs_dsp_op(adev, power, spec->core_init_mask, true);
> +	if (ret < 0)
> +		goto err;
> +
> +	ret = avs_dsp_op(adev, reset, AVS_MAIN_CORE_MASK, false);
> +	if (ret < 0)
> +		goto err;
> +
> +	reinit_completion(&adev->fw_ready);
> +	avs_dsp_op(adev, int_control, true);
> +
> +	/* set boot config */
> +	ret = avs_ipc_set_boot_config(adev, dma_id, purge);
> +	if (ret) {
> +		ret = AVS_IPC_RET(ret);
> +		goto err;
> +	}
> +
> +	/* await ROM init */
> +	ret = snd_hdac_adsp_readq_poll(adev, spec->rom_status, reg,
> +				       (reg & 0xF) == AVS_ROM_INIT_DONE
> ||
> +				       (reg & 0xF) ==
> APL_ROM_FW_ENTERED,
> +				       AVS_ROM_INIT_POLLING_US,
> APL_ROM_INIT_TIMEOUT_US);
> +	if (ret < 0) {
> +		dev_err(adev->dev, "rom init timeout: %d\n", ret);
> +		goto err;
> +	}
> +
> +	/* power down non-main cores */
> +	if (corex_mask)
> +		avs_dsp_op(adev, power, corex_mask, false);
What if this fails?
> +
> +	return 0;
> +
> +err:
> +	avs_dsp_core_disable(adev, spec->core_init_mask);
> +	return ret;
> +}
> +
> +static int avs_imr_load_basefw(struct avs_dev *adev)
> +{
> +	int ret;
> +
> +	/* DMA id ignored when flashing from IMR as no transfer occurs.
> */
> +	ret = avs_hda_init_rom(adev, 0, false);
> +	if (ret < 0) {
> +		dev_err(adev->dev, "rom init failed: %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = wait_for_completion_timeout(&adev->fw_ready,
> +				msecs_to_jiffies(AVS_FW_INIT_TIMEOUT_MS
> ));
> +	if (!ret) {
> +		dev_err(adev->dev, "firmware ready timeout\n");
> +		avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK);
> +		return -ETIMEDOUT;
> +	}
> +
> +	return 0;
> +}
> +
> +int avs_hda_load_basefw(struct avs_dev *adev, struct firmware *fw)
> +{
> +	struct snd_pcm_substream substream;
> +	struct snd_dma_buffer dmab;
> +	struct hdac_ext_stream *estream;
> +	struct hdac_stream *hstream;
> +	struct hdac_bus *bus = &adev->base.core;
> +	unsigned int sdfmt, reg;
> +	int ret, i;
> +
> +	/* configure hda dma */
> +	memset(&substream, 0, sizeof(substream));
> +	substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
> +	estream = snd_hdac_ext_stream_assign(bus, &substream,
> +					     HDAC_EXT_STREAM_TYPE_HOST)
> ;
> +	if (!estream)
> +		return -ENODEV;
> +	hstream = hdac_stream(estream);
> +
> +	/* code loading performed with default format */
> +	sdfmt = snd_hdac_calc_stream_format(48000, 1,
> SNDRV_PCM_FORMAT_S32_LE, 32, 0);
> +	ret = snd_hdac_dsp_prepare(hstream, sdfmt, fw->size, &dmab);
> +	if (ret < 0)
> +		goto release_stream;
> +
> +	/* enable SPIB for hda stream */
> +	snd_hdac_ext_stream_spbcap_enable(bus, true, hstream->index);
> +	ret = snd_hdac_ext_stream_set_spib(bus, estream, fw->size);
> +	if (ret)
> +		goto cleanup_resources;
> +
> +	memcpy(dmab.area, fw->data, fw->size);
> +
> +	for (i = 0; i < APL_ROM_INIT_RETRIES; i++) {
> +		unsigned int dma_id = hstream->stream_tag - 1;
> +
> +		ret = avs_hda_init_rom(adev, dma_id, true);
> +		if (!ret)
> +			break;
> +		dev_info(adev->dev, "#%d rom init fail: %d\n", i + 1,
> ret);
> +	}
> +	if (ret < 0)
> +		goto cleanup_resources;
> +
> +	/* transfer firmware */
> +	snd_hdac_dsp_trigger(hstream, true);
> +	ret = snd_hdac_adsp_readl_poll(adev, AVS_FW_REG_STATUS(adev),
> reg,
> +				       (reg & AVS_ROM_STS_MASK) ==
> APL_ROM_FW_ENTERED,
> +				       AVS_FW_INIT_POLLING_US,
> AVS_FW_INIT_TIMEOUT_US);
> +	snd_hdac_dsp_trigger(hstream, false);
> +	if (ret < 0) {
> +		dev_err(adev->dev, "transfer fw failed: %d\n", ret);
> +		avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK);
> +	}
> +
> +cleanup_resources:
> +	/* disable SPIB for hda stream */
> +	snd_hdac_ext_stream_spbcap_enable(bus, false, hstream->index);
> +	snd_hdac_ext_stream_set_spib(bus, estream, 0);
> +
> +	snd_hdac_dsp_cleanup(hstream, &dmab);
> +release_stream:
> +	snd_hdac_ext_stream_release(estream,
> HDAC_EXT_STREAM_TYPE_HOST);
> +
> +	return ret;
> +}
> +
> +int avs_hda_load_library(struct avs_dev *adev, struct firmware *lib,
> u32 id)
> +{
> +	struct snd_pcm_substream substream;
> +	struct snd_dma_buffer dmab;
> +	struct hdac_ext_stream *estream;
> +	struct hdac_stream *stream;
> +	struct hdac_bus *bus = &adev->base.core;
> +	unsigned int sdfmt;
> +	int ret;
> +
> +	/* configure hda dma */
> +	memset(&substream, 0, sizeof(substream));
> +	substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
> +	estream = snd_hdac_ext_stream_assign(bus, &substream,
> +					     HDAC_EXT_STREAM_TYPE_HOST)
> ;
> +	if (!estream)
> +		return -ENODEV;
> +	stream = hdac_stream(estream);
> +
> +	/* code loading performed with default format */
> +	sdfmt = snd_hdac_calc_stream_format(48000, 1,
> SNDRV_PCM_FORMAT_S32_LE, 32, 0);
> +	ret = snd_hdac_dsp_prepare(stream, sdfmt, lib->size, &dmab);
> +	if (ret < 0)
> +		goto release_stream;
> +
> +	/* enable SPIB for hda stream */
> +	snd_hdac_ext_stream_spbcap_enable(bus, true, stream->index);
> +	snd_hdac_ext_stream_set_spib(bus, estream, lib->size);
> +
> +	memcpy(dmab.area, lib->data, lib->size);
> +
> +	/* transfer firmware */
> +	snd_hdac_dsp_trigger(stream, true);
> +	ret = avs_ipc_load_library(adev, stream->stream_tag - 1, id);
> +	snd_hdac_dsp_trigger(stream, false);
> +	if (ret) {
> +		dev_err(adev->dev, "transfer lib %d failed: %d\n", id,
> ret);
> +		ret = AVS_IPC_RET(ret);
> +	}
> +
> +	/* disable SPIB for hda stream */
> +	snd_hdac_ext_stream_spbcap_enable(bus, false, stream->index);
> +	snd_hdac_ext_stream_set_spib(bus, estream, 0);
> +
> +	snd_hdac_dsp_cleanup(stream, &dmab);
> +release_stream:
> +	snd_hdac_ext_stream_release(estream,
> HDAC_EXT_STREAM_TYPE_HOST);
> +
> +	return ret;
> +}
> +
> +int avs_hda_transfer_modules(struct avs_dev *adev, bool load,
> +			     struct avs_module_entry *mods, u32
> num_mods)
What is the difference between transfer_modules and load_library?

Thanks,Ranjani


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

* Re: [PATCH v3 04/17] ASoC: Intel: avs: Inter process communication
  2022-03-04 16:09   ` Ranjani Sridharan
@ 2022-03-04 17:11     ` Cezary Rojewski
  2022-03-07 16:15       ` Ranjani Sridharan
  0 siblings, 1 reply; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-04 17:11 UTC (permalink / raw)
  To: Ranjani Sridharan, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

On 2022-03-04 5:09 PM, Ranjani Sridharan wrote:
> On Fri, 2022-03-04 at 15:57 +0100, Cezary Rojewski wrote:

...

>> +static inline void avs_ipc_err(struct avs_dev *adev, struct
>> avs_ipc_msg *tx,
>> +			       const char *name, int error)
>> +{
>> +	/*
>> +	 * If IPC channel is blocked e.g.: due to ongoing recovery,
> Do you mean firmware recovery? In which cases do you perform a
> recovery?

Thanks for feedback! Consider dropping the unnecessary bits so it is 
easier to navigate through your responses.

Please note: kernel mailing list is not for explaining SW <-> FW 
communication details. Feel free to contact my colleagues from firmware 
team if in need of any FW-iface details.

That goes for most of the comments found below too.

-

Yes, I mean firmware recovery here. Code found in this patchset shows 
that message timeout is one of the reasons.

>> +	 * -EPERM error code is expected and thus it's not an actual
>> error.
> And what happens in this case? do you retry the IPC after recovery?


Not at all. Why would you want retry IPC after recovery in the first place?

>> +	 */
>> +	if (error == -EPERM)
>> +		dev_dbg(adev->dev, "%s 0x%08x 0x%08x failed: %d\n",
>> name,
>> +			tx->glb.primary, tx->glb.ext.val, error);
>> +	else
>> +		dev_err(adev->dev, "%s 0x%08x 0x%08x failed: %d\n",
>> name,
>> +			tx->glb.primary, tx->glb.ext.val, error);
>> +}
>> +
>> +irqreturn_t avs_dsp_irq_handler(int irq, void *dev_id);
>> +irqreturn_t avs_dsp_irq_thread(int irq, void *dev_id);
>> +void avs_dsp_process_response(struct avs_dev *adev, u64 header);
>> +int avs_dsp_send_msg_timeout(struct avs_dev *adev,
>> +			     struct avs_ipc_msg *request,
>> +			     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);
>> +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);
>> +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);
>> +
>>   #endif /* __SOUND_SOC_INTEL_AVS_H */
>> diff --git a/sound/soc/intel/avs/ipc.c b/sound/soc/intel/avs/ipc.c
>> new file mode 100644
>> index 000000000000..c0722f8b195f
>> --- /dev/null
>> +++ b/sound/soc/intel/avs/ipc.c
>> @@ -0,0 +1,387 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +//
>> +// Copyright(c) 2021 Intel Corporation. All rights reserved.
>> +//
>> +// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
>> +//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
>> +//
>> +
>> +#include <linux/slab.h>
>> +#include <sound/hdaudio_ext.h>
>> +#include "avs.h"
>> +#include "messages.h"
>> +#include "registers.h"
>> +
>> +#define AVS_IPC_TIMEOUT_MS	300
>> +
>> +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);
>> +
>> +	ipc->rx.header = header;
>> +	/* Abort copying payload if request processing was
>> unsuccessful. */
> This seems misplaced? Why would you called this function is the status
> showed an error?


This comment is part of Pierre's feedback, not misplaced at all.

Header can be message-specific and contain valid info to perform even on 
failure.

>> +	if (!msg.status)
>> +		memcpy_fromio(ipc->rx.data, avs_uplink_addr(adev),
>> +			      ipc->rx.size);
>> +}
>> +
>> +static void avs_dsp_process_notification(struct avs_dev *adev, u64
>> header)
>> +{
>> +	struct avs_notify_mod_data mod_data;
>> +	union avs_notify_msg msg = AVS_MSG(header);
>> +	size_t data_size = 0;
>> +	void *data = NULL;
>> +
>> +	/* Ignore spurious notifications until handshake is
>> established. */
>> +	if (!adev->ipc->ready && msg.notify_msg_type !=
>> AVS_NOTIFY_FW_READY) {
>> +		dev_dbg(adev->dev, "FW not ready, skip notification:
>> 0x%08x\n",
>> +			msg.primary);
>> +		return;
>> +	}
>> +
>> +	/* Calculate notification payload size. */
>> +	switch (msg.notify_msg_type) {
>> +	case AVS_NOTIFY_FW_READY:
>> +		break;
>> +
>> +	case AVS_NOTIFY_PHRASE_DETECTED:
>> +		data_size = sizeof(struct avs_notify_voice_data);
>> +		break;
>> +
>> +	case AVS_NOTIFY_RESOURCE_EVENT:
>> +		data_size = sizeof(struct avs_notify_res_data);
>> +		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));
>> +		data_size = sizeof(mod_data) + mod_data.data_size;
>> +		break;
>> +
>> +	default:
>> +		dev_info(adev->dev, "unknown notification: 0x%08x\n",
>> +			 msg.primary);
> info? should it be a warning?


Pierre's feedback was exactly the opposite.

>> +		break;
>> +	}
>> +
>> +	if (data_size) {
>> +		data = kmalloc(data_size, GFP_KERNEL);
>> +		if (!data)
>> +			return;
> Should this function be modified to return the error? If it failed
> here, all subsequent IPC's rec'd will also fail isnt it?


Hmm.. we are servicing an IPC here, can't return an error code, really. 
Also, some memory could have been freed between IRQs.

>> +
>> +		memcpy_fromio(data, avs_uplink_addr(adev), data_size);
>> +	}
>> +
>> +	/* Perform notification-specific operations. */
>> +	switch (msg.notify_msg_type) {
>> +	case AVS_NOTIFY_FW_READY:
>> +		dev_dbg(adev->dev, "FW READY 0x%08x\n", msg.primary);
>> +		adev->ipc->ready = true;
>> +		complete(&adev->fw_ready);
>> +		break;
>> +
>> +	default:
>> +		break;
>> +	}
>> +
>> +	kfree(data);
> You alloc memory for "data", copy the data and free it? Where is it
> used?


This patch implement the backbone for the entire IPC protocol. Specific 
handlers are not found here.

>> +static void avs_ipc_msg_init(struct avs_ipc *ipc, struct avs_ipc_msg
>> *reply)
>> +{
>> +	lockdep_assert_held(&ipc->rx_lock);
>> +
>> +	ipc->rx.header = 0;
>> +	ipc->rx.size = reply ? reply->size : 0;
>> +	ipc->rx_completed = false;
>> +
>> +	reinit_completion(&ipc->done_completion);
>> +	reinit_completion(&ipc->busy_completion);
>> +}
>> +
>> +static void avs_dsp_send_tx(struct avs_dev *adev, struct avs_ipc_msg
>> *tx)
> send_tx? send and tx both imply the same isnt it? maybe just use one or
> the other?


Matter of taste I believe. Also, aligned with the catpt-driver.

>> +static int avs_dsp_do_send_msg(struct avs_dev *adev, struct
>> avs_ipc_msg *request,
>> +			       struct avs_ipc_msg *reply, int timeout)
>> +{
>> +	struct avs_ipc *ipc = adev->ipc;
>> +	int ret;
>> +
>> +	if (!ipc->ready)
>> +		return -EPERM;
>> +
>> +	mutex_lock(&ipc->msg_mutex);
>> +
>> +	spin_lock(&ipc->rx_lock);
>> +	avs_ipc_msg_init(ipc, reply);
>> +	avs_dsp_send_tx(adev, request);
>> +	spin_unlock(&ipc->rx_lock);
>> +
>> +	ret = avs_ipc_wait_busy_completion(ipc, timeout);
>> +	if (ret) {
>> +		if (ret == -ETIMEDOUT) {
>> +			dev_crit(adev->dev, "communication severed: %d,
>> rebooting dsp..\n",
> Where does this reboot happen?


This patch implement the backbone for the entire IPC protocol. Specific 
handlers are not found here. Message remained.


Regards,
Czarek

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

* Re: [PATCH v3 06/17] ASoC: Intel: avs: Add pipeline management requests
  2022-03-04 16:13   ` Ranjani Sridharan
@ 2022-03-04 17:15     ` Cezary Rojewski
  0 siblings, 0 replies; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-04 17:15 UTC (permalink / raw)
  To: Ranjani Sridharan, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

On 2022-03-04 5:13 PM, Ranjani Sridharan wrote:
> On Fri, 2022-03-04 at 15:57 +0100, Cezary Rojewski wrote:
>> Pipeline represents a scheduling entity. Their existence as well as
>> their state machine is controlled through CREATE_PIPELINE,
>> DELETE_PIPELINE and SET_PIPELINE_STATE IPCs.

...

>> +int avs_ipc_set_pipeline_state(struct avs_dev *adev, u8 instance_id,
>> +			       enum avs_pipeline_state state)
>> +{
>> +	union avs_global_msg msg =
>> AVS_GLOBAL_REQUEST(SET_PIPELINE_STATE);
>> +	struct avs_ipc_msg request = {{0}};
>> +	int ret;
>> +
>> +	msg.set_ppl_state.ppl_id = instance_id;
>> +	msg.set_ppl_state.state = state;
>> +	request.header = msg.val;
>> +
>> +	ret = avs_dsp_send_msg(adev, &request, NULL);
>> +	if (ret)
>> +		avs_ipc_err(adev, &request, "set pipeline state", ret);
>> +
>> +	return ret;
>> +}
>> +
>> +int avs_ipc_get_pipeline_state(struct avs_dev *adev, u8 instance_id,
>> +			       enum avs_pipeline_state *state)
> Can the pipeline state in the firmware change without the driver's
> knowledge? When should the driver use this get_pipeline_state()?


Thanks for feedback! Consider dropping the unnecessary bits so it is 
easier to navigate through your responses.

Please note: kernel mailing list is not for explaining SW <-> FW 
communication details. Feel free to contact my colleagues from firmware 
team if in need of any FW-iface details.

-

Actual state machine is found in the firmware, not in the driver. Driver 
may use such information when profiling and also during debug.


Regards,
Czarek

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

* Re: [PATCH v3 07/17] ASoC: Intel: avs: Add module management requests
  2022-03-04 16:21   ` Ranjani Sridharan
@ 2022-03-04 17:21     ` Cezary Rojewski
  2022-03-07 16:39       ` Ranjani Sridharan
  0 siblings, 1 reply; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-04 17:21 UTC (permalink / raw)
  To: Ranjani Sridharan, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

On 2022-03-04 5:21 PM, Ranjani Sridharan wrote:
> On Fri, 2022-03-04 at 15:57 +0100, Cezary Rojewski wrote:

...

>> +/*
>> + * avs_ipc_delete_instance - Delete module instance
>> + *
>> + * @adev: Driver context
>> + * @module_id: Module-type id
>> + * @instance_id: Unique module instance id
>> + *
>> + * Argument verification, as well as pipeline state checks are done
>> by the
>> + * firmware.
>> + *
>> + * Note: only standalone modules i.e. without a parent pipeline
>> shall be
>> + * deleted using this IPC message. In all other cases, pipeline
>> owning the
>> + * modules peforms cleanup automatically when it is deleted.
> Can you please provide an example of such stand-alone modules? If they
> aren't part of any pipeline, how do they get scheduled?


Thanks for feedback! Consider dropping the unnecessary bits so it is 
easier to navigate through your responses.

Please note: kernel mailing list is not for explaining SW <-> FW 
communication details. Feel free to contact my colleagues from firmware 
team if in need of any FW-iface details.

That goes for most of the comments found below too.

>> +/*
>> + * avs_ipc_unbind - Unbind two module instances
>> + *
>> + * @adev: Driver context
>> + * @module_id: Source module-type id
>> + * @instance_id: Source module instance id
>> + * @dst_module_id: Sink module-type id
>> + * @dst_instance_id: Sink module instance id
>> + * @dst_queue: Sink module pin to unbind @src_queue from
>> + * @src_queue: Source module pin to unbind @dst_queue from
>> + */
> Are there any rules for unbinding? For example if you have 2 modules
> connected to a mixer? Can you unbind the module belonging to the host
> pipeline that is getting stopped while the mixer is still active?


Here we have just a delegate. All the rules are defined and enforced by 
the firmware.

>> +int avs_ipc_unbind(struct avs_dev *adev, u16 module_id, u8
>> instance_id,
>> +		   u16 dst_module_id, u8 dst_instance_id,
>> +		   u8 dst_queue, u8 src_queue)
>> +{
>> +	union avs_module_msg msg = AVS_MODULE_REQUEST(UNBIND);
>> +	struct avs_ipc_msg request = {{0}};
>> +	int ret;
>> +
>> +	msg.module_id = module_id;
>> +	msg.instance_id = instance_id;
>> +	msg.ext.bind_unbind.dst_module_id = dst_module_id;
>> +	msg.ext.bind_unbind.dst_instance_id = dst_instance_id;
>> +	msg.ext.bind_unbind.dst_queue = dst_queue;
>> +	msg.ext.bind_unbind.src_queue = src_queue;
>> +	request.header = msg.val;
>> +
>> +	ret = avs_dsp_send_msg(adev, &request, NULL);
>> +	if (ret)
>> +		avs_ipc_err(adev, &request, "unbind modules", ret);
>> +
>> +	return ret;
>> +}

...

>> +int avs_ipc_get_large_config(struct avs_dev *adev, u16 module_id, u8
>> instance_id,
>> +			     u8 param_id, u8 *request_data, size_t
>> request_size,
>> +			     u8 **reply_data, size_t *reply_size)
>> +{
>> +	union avs_module_msg msg =
>> AVS_MODULE_REQUEST(LARGE_CONFIG_GET);
>> +	struct avs_ipc_msg request;
>> +	struct avs_ipc_msg reply = {{0}};
>> +	size_t size;
>> +	void *buf;
>> +	int ret;
>> +
>> +	reply.data = kzalloc(AVS_MAILBOX_SIZE, GFP_KERNEL);
>> +	if (!reply.data)
>> +		return -ENOMEM;
>> +
>> +	msg.module_id = module_id;
>> +	msg.instance_id = instance_id;
>> +	msg.ext.large_config.data_off_size = request_size;
>> +	msg.ext.large_config.large_param_id = param_id;
>> +	/* final_block is always 0 on request. Updated by fw on reply.
>> */
>> +	msg.ext.large_config.final_block = 0;
>> +	msg.ext.large_config.init_block = 1;
>> +
>> +	request.header = msg.val;
>> +	request.data = request_data;
>> +	request.size = request_size;
>> +	reply.size = AVS_MAILBOX_SIZE;
>> +
>> +	ret = avs_dsp_send_msg(adev, &request, &reply);
>> +	if (ret) {
>> +		avs_ipc_err(adev, &request, "large config get", ret);
>> +		kfree(reply.data);
>> +		return ret;
>> +	}
> How come you dont have a loop here? What if the rec'd data size if
> larger than the max size of IP payload?


That's not how LARGE_CONFIG_GET message works. There is no looping 
involved or expected by the firmware and so we don't have it here.


Regards,
Czarek

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

* Re: [PATCH v3 08/17] ASoC: Intel: avs: Add power management requests
  2022-03-04 16:24   ` Ranjani Sridharan
@ 2022-03-04 17:30     ` Cezary Rojewski
  0 siblings, 0 replies; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-04 17:30 UTC (permalink / raw)
  To: Ranjani Sridharan, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

On 2022-03-04 5:24 PM, Ranjani Sridharan wrote:
> On Fri, 2022-03-04 at 15:57 +0100, Cezary Rojewski wrote:

...

>> +int avs_ipc_set_dx(struct avs_dev *adev, u32 core_mask, bool
>> powerup)
> a description for this function would be helpful.


Both relevant fields have comments as requested by Pierre.

We put quite an effort - which was triggered thanks to the feedback 
received - to have plain, simple delegates in form of: set necessary 
bits and let firmware to its job. I believe SET_DX is a good example of 
such.

>> +{
>> +	union avs_module_msg msg = AVS_MODULE_REQUEST(SET_DX);
>> +	struct avs_ipc_msg request;
>> +	struct avs_dxstate_info dx;
>> +	int ret;
>> +
>> +	dx.core_mask = core_mask;
>> +	dx.dx_mask = powerup ? core_mask : 0;
>> +	request.header = msg.val;
>> +	request.data = &dx;
>> +	request.size = sizeof(dx);
>> +
>> +	ret = avs_dsp_send_msg(adev, &request, NULL);
>> +	if (ret)
>> +		avs_ipc_err(adev, &request, "set dx", ret);
>> +
>> +	return ret;
>> +}
>> +
>> +/*
>> + * avs_ipc_set_d0ix - Set power gating policy (entering D0IX
>> substates)
>> + *
>> + * @enable_pg: Whether to enable or disable power gating
>> + * @streaming: Whether a stream is running when transitioning
>> + */
> What do you mean why "whether a stream is running" does it mean any
> stream? What is the difference between a D0ix transition with a stream
> running compared to not running?


Precisely, any stream. The transition details are found within the 
firmware. Host (the driver) is responsible for scheduling and requesting 
the transition. Nothing more, nothing less.


Regards,
Czarek

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

* Re: [PATCH v3 09/17] ASoC: Intel: avs: Add ROM requests
  2022-03-04 16:26   ` Ranjani Sridharan
@ 2022-03-04 17:33     ` Cezary Rojewski
  0 siblings, 0 replies; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-04 17:33 UTC (permalink / raw)
  To: Ranjani Sridharan, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

On 2022-03-04 5:26 PM, Ranjani Sridharan wrote:
> On Fri, 2022-03-04 at 15:57 +0100, Cezary Rojewski wrote:
>> ROM requests are messages initiated by Host to alter firmware early
>> boot
>> process. They specify whether the next boot should be a fresh start
>> or if
>> IMR can be used to speed things up.
>>
>> 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/messages.c | 18 ++++++++++++++++++
>>   sound/soc/intel/avs/messages.h | 14 ++++++++++++++
>>   2 files changed, 32 insertions(+)
>>
>> diff --git a/sound/soc/intel/avs/messages.c
>> b/sound/soc/intel/avs/messages.c
>> index e8f441b28d71..f7d00e541323 100644
>> --- a/sound/soc/intel/avs/messages.c
>> +++ b/sound/soc/intel/avs/messages.c
>> @@ -12,6 +12,24 @@
>>   
>>   #define AVS_CL_TIMEOUT_MS	5000
>>   
>> +int avs_ipc_set_boot_config(struct avs_dev *adev, u32 dma_id, u32
>> purge)
> Does purge set to true indicate a fresh boot and a false indicate IMR
> restore? A description would help.


Indeed, purge indicates a fresh boot.

I believe flow is explained well by the layout of the calling functions, 
local variable naming and step-ordering which are found later in the series.


Regards,
Czarek

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

* Re: [PATCH v3 10/17] ASoC: Intel: avs: Add basefw runtime-parameter requests
  2022-03-04 16:31   ` Ranjani Sridharan
@ 2022-03-04 17:37     ` Cezary Rojewski
  2022-03-07 16:41       ` Ranjani Sridharan
  0 siblings, 1 reply; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-04 17:37 UTC (permalink / raw)
  To: Ranjani Sridharan, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

On 2022-03-04 5:31 PM, Ranjani Sridharan wrote:
> On Fri, 2022-03-04 at 15:57 +0100, Cezary Rojewski wrote:

...

>> +int avs_ipc_get_fw_config(struct avs_dev *adev, struct avs_fw_cfg
>> *cfg)
>> +{
>> +	struct avs_tlv *tlv;
>> +	size_t payload_size;
>> +	size_t offset = 0;
>> +	u8 *payload;
>> +	int ret;
>> +
>> +	ret = avs_ipc_get_large_config(adev, AVS_BASEFW_MOD_ID,
>> AVS_BASEFW_INST_ID,
>> +				       AVS_BASEFW_FIRMWARE_CONFIG,
>> NULL, 0,
>> +				       &payload, &payload_size);
>> +	if (ret)
>> +		return ret;
>> +
>> +	while (offset < payload_size) {
>> +		tlv = (struct avs_tlv *)(payload + offset);
>> +
>> +		switch (tlv->type) {
>> +		case AVS_FW_CFG_FW_VERSION:
>> +			memcpy(&cfg->fw_version, tlv->value,
>> +				sizeof(cfg->fw_version));
>> +			break;
>> +
>> +		case AVS_FW_CFG_MEMORY_RECLAIMED:
>> +			cfg->memory_reclaimed = *tlv->value;
>> +			break;
>> +
>> +		case AVS_FW_CFG_SLOW_CLOCK_FREQ_HZ:
>> +			cfg->slow_clock_freq_hz = *tlv->value;
>> +			break;
>> +
>> +		case AVS_FW_CFG_FAST_CLOCK_FREQ_HZ:
>> +			cfg->fast_clock_freq_hz = *tlv->value;
>> +			break;
>> +
>> +		case AVS_FW_CFG_ALH_SUPPORT_LEVEL:
>> +			cfg->alh_support = *tlv->value;
>> +			break;
>> +
>> +		case AVS_FW_CFG_IPC_DL_MAILBOX_BYTES:
>> +			cfg->ipc_dl_mailbox_bytes = *tlv->value;
>> +			break;
>> +
>> +		case AVS_FW_CFG_IPC_UL_MAILBOX_BYTES:
>> +			cfg->ipc_ul_mailbox_bytes = *tlv->value;
>> +			break;
>> +
>> +		case AVS_FW_CFG_TRACE_LOG_BYTES:
>> +			cfg->trace_log_bytes = *tlv->value;
>> +			break;
>> +
>> +		case AVS_FW_CFG_MAX_PPL_COUNT:
>> +			cfg->max_ppl_count = *tlv->value;
>> +			break;
>> +
>> +		case AVS_FW_CFG_MAX_ASTATE_COUNT:
>> +			cfg->max_astate_count = *tlv->value;
>> +			break;
>> +
>> +		case AVS_FW_CFG_MAX_MODULE_PIN_COUNT:
>> +			cfg->max_module_pin_count = *tlv->value;
>> +			break;
>> +
>> +		case AVS_FW_CFG_MODULES_COUNT:
>> +			cfg->modules_count = *tlv->value;
>> +			break;
>> +
>> +		case AVS_FW_CFG_MAX_MOD_INST_COUNT:
>> +			cfg->max_mod_inst_count = *tlv->value;
>> +			break;
>> +
>> +		case AVS_FW_CFG_MAX_LL_TASKS_PER_PRI_COUNT:
>> +			cfg->max_ll_tasks_per_pri_count = *tlv->value;
>> +			break;
>> +
>> +		case AVS_FW_CFG_LL_PRI_COUNT:
>> +			cfg->ll_pri_count = *tlv->value;
>> +			break;
>> +
>> +		case AVS_FW_CFG_MAX_DP_TASKS_COUNT:
>> +			cfg->max_dp_tasks_count = *tlv->value;
>> +			break;
>> +
>> +		case AVS_FW_CFG_MAX_LIBS_COUNT:
>> +			cfg->max_libs_count = *tlv->value;
>> +			break;
>> +
>> +		case AVS_FW_CFG_XTAL_FREQ_HZ:
>> +			cfg->xtal_freq_hz = *tlv->value;
>> +			break;
>> +
>> +		case AVS_FW_CFG_POWER_GATING_POLICY:
>> +			cfg->power_gating_policy = *tlv->value;
>> +			break;
>> +
>> +		/* Known but not useful to us. */
>> +		case AVS_FW_CFG_DMA_BUFFER_CONFIG:
>> +		case AVS_FW_CFG_SCHEDULER_CONFIG:
>> +		case AVS_FW_CFG_CLOCKS_CONFIG:
>> +			break;
>> +
>> +		default:
>> +			dev_info(adev->dev, "Unrecognized fw param:
>> %d\n",
>> +				 tlv->type);
>> +			break;
>> +		}
>> +
>> +		offset += sizeof(*tlv) + tlv->length;
>> +	}
>> +
>> +	kfree(payload);
> I think it would be easier to understand this kfree if payload was also
> allocated in this function in stead of inside the get_large_config().


That's a good thinking. There was an internal conversation regarding 
this back in time when we have been implementing getters for the first 
time. There are no clear victors, there are drawbacks - as you do not 
know the size upfront, caller has to guess and then reallocate the 
buffer accordingly to retrieved payload size from the firmware. So, even 
if you allocate buffer here, chances are, it's not the same buffer when 
the avs_ipc_get_large_config() returns to the caller.

We have decided to reduce the code size by letting the single, common 
handler do the allocation and leave the other responsibilities to the 
caller.


Regards,
Czarek

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

* Re: [PATCH v3 11/17] ASoC: Intel: avs: Firmware resources management utilities
  2022-03-04 16:41   ` Ranjani Sridharan
@ 2022-03-04 18:02     ` Cezary Rojewski
  2022-03-07 16:46       ` Ranjani Sridharan
  0 siblings, 1 reply; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-04 18:02 UTC (permalink / raw)
  To: Ranjani Sridharan, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

On 2022-03-04 5:41 PM, Ranjani Sridharan wrote:
> On Fri, 2022-03-04 at 15:57 +0100, Cezary Rojewski wrote:

>>   /*
>>    * struct avs_dev - Intel HD-Audio driver data
>>    *
>>    * @dev: PCI device
>>    * @dsp_ba: DSP bar address
>>    * @spec: platform-specific descriptor
>> + * @fw_cfg: Firmware configuration, obtained through FW_CONFIG
>> message
>> + * @hw_cfg: Hardware configuration, obtained through HW_CONFIG
>> message
>> + * @mods_info: Available module-types, obtained through MODULES_INFO
>> message
>> + * @mod_idas: Module instance ID pool, one per module-type
>> + * @modres_mutex: For synchronizing any @mods_info updates
> Is this mutex really necessary? Can you please elaborate under what
> circumstances your will have parallel module updates?


Yes, we believe modres_mutex is necessary. All information regarding 
modules exposed by the firmware are stored within ->mods_info cache.

That's just a snapshot though. When a new library gets loaded, new 
modules may be available for use and so the driver updates the 
->mods_info cache to have the latest snapshot. As information found 
there is used when streaming (e.g.: instantiating modules), we enter a 
scenario when multiple threads could be reading/updating the ->mods_info 
at once. To prevent any unwanted behavior, mutex has been added.

>> +void avs_module_info_free(struct avs_dev *adev)
>> +{
>> +	mutex_lock(&adev->modres_mutex);
>> +
>> +	avs_module_ida_destroy(adev);
>> +	kfree(adev->mods_info);
>> +	adev->mods_info = NULL;
>> +
>> +	mutex_unlock(&adev->modres_mutex);
>> +}
>> +
>> +int avs_module_id_alloc(struct avs_dev *adev, u16 module_id)
>> +{
>> +	int ret, idx, max_id;
>> +
>> +	mutex_lock(&adev->modres_mutex);
>> +
>> +	idx = avs_module_id_entry_index(adev, module_id);
>> +	if (idx == -ENOENT) {
> Can you please help me understand when this can happen? If all modules
> required by the topology are already initialized, will this ever
> happen?


I want to help! Just not understanding the meaning of: "all modules 
required by the topology are already initialized".

Will answer best I can though: topology carries just patterns, it may 
happen that module found within topology file is not actually exposed by 
the firmware. In such case, we drop an error. This keeps recovery 
scenarios sane too - when recovering, libraries may have to be 
re-loaded, depending on the firmware generation and whether basefw 
recovery was successful or not.


Regards,
Czarek

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

* Re: [PATCH v3 12/17] ASoC: Intel: avs: Declare module configuration types
  2022-03-04 16:43   ` Ranjani Sridharan
@ 2022-03-04 18:10     ` Cezary Rojewski
  0 siblings, 0 replies; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-04 18:10 UTC (permalink / raw)
  To: Ranjani Sridharan, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

On 2022-03-04 5:43 PM, Ranjani Sridharan wrote:
> On Fri, 2022-03-04 at 15:57 +0100, Cezary Rojewski wrote:

>> +#define AVS_INTELWOV_MOD_UUID \
>> +	GUID_INIT(0xEC774FA9, 0x28D3, 0x424A, 0x90, 0xE4, 0x69, 0xF9,
>> 0x84, 0xF1, 0xEE, 0xB7)
> Why do you need to hard-code this? DOes the fw config info that you
> retrieve using get_large_config or even the FW manifest have it
> already?

While I can't get into the details, the problem lies within the firmware 
binary itself e.g.: copier may have module ID of 3 in case of firmware 
generation X, but ID of 4 in generation Y. The only sane option are the 
GUIDs - these have never changed.

Even when reading manifest, driver has to have some kind of method to 
understand what is it reading. If one cannot trust any enum or constant, 
then one won't know it is reading copier anyway. GUID list is the 
necessary evil here as we have no options of repairing all the firmware 
generations.

We do make a snapshot of modules info data through LARGE_CONFIG_GET and 
store it within ->mods_info for later use, yes (stream runtime).


Regards,
Czarek

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

* Re: [PATCH v3 13/17] ASoC: Intel: avs: Dynamic firmware resources management
  2022-03-04 16:47   ` Ranjani Sridharan
@ 2022-03-04 18:15     ` Cezary Rojewski
  0 siblings, 0 replies; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-04 18:15 UTC (permalink / raw)
  To: Ranjani Sridharan, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

On 2022-03-04 5:47 PM, Ranjani Sridharan wrote:
> On Fri, 2022-03-04 at 15:57 +0100, Cezary Rojewski wrote:
>> Wrap elementary DSP-core operations and resource control into more
>> complex handlers. This is done to reduce the number of invocations of
>> wrapped operations throughout the driver as order of operations
>> matters -
>> most flows involve register manipulation and IPCs combined.
>>
>> 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 |  10 +++
>>   sound/soc/intel/avs/dsp.c | 170
>> ++++++++++++++++++++++++++++++++++++++
>>   2 files changed, 180 insertions(+)
>>
>> diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h
>> index 02d7591d0eac..0034c075fa64 100644
>> --- a/sound/soc/intel/avs/avs.h
>> +++ b/sound/soc/intel/avs/avs.h
>> @@ -89,6 +89,7 @@ struct avs_dev {
>>   	struct mutex modres_mutex;
>>   	struct ida ppl_ida;
>>   	struct list_head fw_list;
>> +	int *core_refs;
> 
> Is this a per core ref_count? a comment or explicitly calling it
> core_ref_count would help.


Hmm.. That's bit of a nitpick. Isn't a 's' enough here? I.e.: here we 
have an array of core references. Array, as the number of elements is 
retrieved dynamically via LARGE_CONFIG_GET and only then the array gets 
allocated.


Regards,
Czarek

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

* Re: [PATCH v3 14/17] ASoC: Intel: avs: General code loading flow
  2022-03-04 16:54   ` Ranjani Sridharan
@ 2022-03-04 18:29     ` Cezary Rojewski
  0 siblings, 0 replies; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-04 18:29 UTC (permalink / raw)
  To: Ranjani Sridharan, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

On 2022-03-04 5:54 PM, Ranjani Sridharan wrote:
> On Fri, 2022-03-04 at 15:57 +0100, Cezary Rojewski wrote:

...

>> +static int avs_fw_manifest_strip_verify(struct avs_dev *adev, struct
>> firmware *fw,
>> +					const struct avs_fw_version
>> *min)
>> +{
>> +	struct avs_fw_manifest *man;
>> +	int offset, ret;
>> +
>> +	ret = avs_fw_ext_manifest_strip(fw);
>> +	if (ret)
>> +		return ret;
>> +
>> +	offset = avs_fw_manifest_offset(fw);
>> +	if (offset < 0)
>> +		return offset;
>> +
>> +	if (fw->size < offset + sizeof(*man))
>> +		return -EINVAL;
>> +	if (!min)
>> +		return 0;
>> +
>> +	man = (struct avs_fw_manifest *)(fw->data + offset);
>> +	if (man->version.major != min->major ||
>> +	    man->version.minor != min->minor ||
>> +	    man->version.hotfix != min->hotfix ||
>> +	    man->version.build < min->build) {
> Isnt this check a bit too strict? Isnt a check major enough?


Unfortunately not. I share the similar thinking but the build system has 
its history and several things which should not happen, had happened. 
There could be _large_ API changes without any meaningful version 
updates at all. To prevent any unwanted behavior, this check is as 
strict as it can get.

>> +		dev_warn(adev->dev, "bad FW version %d.%d.%d.%d,
>> expected %d.%d.%d.%d or newer\n",
>> +			 man->version.major, man->version.minor,
>> +			 man->version.hotfix, man->version.build,
>> +			 min->major, min->minor, min->hotfix, min-
>>> build);
>> +
>> +		if (!debug_ignore_fw_version)
>> +			return -EINVAL;
>> +	}
>> +
>> +	return 0;
>> +}

...

>> +int avs_dsp_boot_firmware(struct avs_dev *adev, bool purge)
>> +{
>> +	int ret, i;
>> +
>> +	/* Full boot, clear cached data except for basefw (slot 0). */
> Does this mean IMR restore is only available for base FW and not for
> module libraries? Do I understand this correctly?


Loop below just clears the data. The new snapshot will be received once 
the basefw and libraries get loaded. The execution of library loading is 
not part of this patch anymore as it is dependent on the 
avs-soc-component stuff. To make things easier to review, request was to 
split main series into chucks. I do believe it is easier to read and 
review indeed.

>> +	for (i = 1; i < adev->fw_cfg.max_libs_count; i++)
>> +		memset(adev->lib_names[i], 0, AVS_LIB_NAME_SIZE);
>> +
>> +	avs_hda_clock_gating_enable(adev, false);
>> +	avs_hda_l1sen_enable(adev, false);
>> +
>> +	ret = avs_dsp_load_basefw(adev);
>> +
>> +	avs_hda_l1sen_enable(adev, true);
>> +	avs_hda_clock_gating_enable(adev, true);
>> +
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	/* With all code loaded, refresh module information. */
>> +	ret = avs_module_info_init(adev, true);
> It is not clear if this required only after first boot or after a
> suspend/resume as well.


avs_dsp_boot_firmware() and avs_dsp_first_boot_firmware() (found just 
below this one) are two separate functions. Only the latter has things 
done once. Anything else can happen several times throughout the 
lifetime of the avs-driver.


Regards,
Czarek

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

* Re: [PATCH v3 17/17] ASoC: Intel: avs: Code loading over HDA
  2022-03-04 16:59   ` Ranjani Sridharan
@ 2022-03-04 18:44     ` Cezary Rojewski
  2022-03-04 18:56       ` Pierre-Louis Bossart
  0 siblings, 1 reply; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-04 18:44 UTC (permalink / raw)
  To: Ranjani Sridharan, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

On 2022-03-04 5:59 PM, Ranjani Sridharan wrote:
> On Fri, 2022-03-04 at 15:57 +0100, Cezary Rojewski wrote:
>> Compared to SKL and KBL, younger cAVS platforms are meant to re-use
>> one
> Younger? you mean newer?


Isn't the meaning of the two quite similar in this context?

>> of HDAudio streams during boot procedure causing CLDMA to become
>> obsolete. Once transferred, given stream is returned to pool
>> available
>> for audio streaming.
>>
>> Module loading handler is dummy as library and module code became
>> inseparable in later firmware generations.
> replace dummy with "stub" maybe? lets use inclusive terms


Is 'dummy' categorized as non-inclusive? We have several usages of 
'dummy' even within /sound (e.g. soc-utils.c).

>> +static int
>> +avs_hda_init_rom(struct avs_dev *adev, unsigned int dma_id, bool
>> purge)
>> +{
>> +	const struct avs_spec *const spec = adev->spec;
>> +	unsigned int corex_mask, reg;
>> +	int ret;
>> +
>> +	corex_mask = spec->core_init_mask & ~AVS_MAIN_CORE_MASK;
>> +
>> +	ret = avs_dsp_op(adev, power, spec->core_init_mask, true);
>> +	if (ret < 0)
>> +		goto err;
>> +
>> +	ret = avs_dsp_op(adev, reset, AVS_MAIN_CORE_MASK, false);
>> +	if (ret < 0)
>> +		goto err;
>> +
>> +	reinit_completion(&adev->fw_ready);
>> +	avs_dsp_op(adev, int_control, true);
>> +
>> +	/* set boot config */
>> +	ret = avs_ipc_set_boot_config(adev, dma_id, purge);
>> +	if (ret) {
>> +		ret = AVS_IPC_RET(ret);
>> +		goto err;
>> +	}
>> +
>> +	/* await ROM init */
>> +	ret = snd_hdac_adsp_readq_poll(adev, spec->rom_status, reg,
>> +				       (reg & 0xF) == AVS_ROM_INIT_DONE
>> ||
>> +				       (reg & 0xF) ==
>> APL_ROM_FW_ENTERED,
>> +				       AVS_ROM_INIT_POLLING_US,
>> APL_ROM_INIT_TIMEOUT_US);
>> +	if (ret < 0) {
>> +		dev_err(adev->dev, "rom init timeout: %d\n", ret);
>> +		goto err;
>> +	}
>> +
>> +	/* power down non-main cores */
>> +	if (corex_mask)
>> +		avs_dsp_op(adev, power, corex_mask, false);
> What if this fails?


We are still in happy path, worst thing could happen here is increased 
power consumption.

>> +
>> +	return 0;
>> +
>> +err:
>> +	avs_dsp_core_disable(adev, spec->core_init_mask);
>> +	return ret;
>> +}
>> +

...

>> +int avs_hda_load_library(struct avs_dev *adev, struct firmware *lib,
>> u32 id)
>> +{
>> +	struct snd_pcm_substream substream;
>> +	struct snd_dma_buffer dmab;
>> +	struct hdac_ext_stream *estream;
>> +	struct hdac_stream *stream;
>> +	struct hdac_bus *bus = &adev->base.core;
>> +	unsigned int sdfmt;
>> +	int ret;
>> +
>> +	/* configure hda dma */
>> +	memset(&substream, 0, sizeof(substream));
>> +	substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
>> +	estream = snd_hdac_ext_stream_assign(bus, &substream,
>> +					     HDAC_EXT_STREAM_TYPE_HOST)
>> ;
>> +	if (!estream)
>> +		return -ENODEV;
>> +	stream = hdac_stream(estream);
>> +
>> +	/* code loading performed with default format */
>> +	sdfmt = snd_hdac_calc_stream_format(48000, 1,
>> SNDRV_PCM_FORMAT_S32_LE, 32, 0);
>> +	ret = snd_hdac_dsp_prepare(stream, sdfmt, lib->size, &dmab);
>> +	if (ret < 0)
>> +		goto release_stream;
>> +
>> +	/* enable SPIB for hda stream */
>> +	snd_hdac_ext_stream_spbcap_enable(bus, true, stream->index);
>> +	snd_hdac_ext_stream_set_spib(bus, estream, lib->size);
>> +
>> +	memcpy(dmab.area, lib->data, lib->size);
>> +
>> +	/* transfer firmware */
>> +	snd_hdac_dsp_trigger(stream, true);
>> +	ret = avs_ipc_load_library(adev, stream->stream_tag - 1, id);
>> +	snd_hdac_dsp_trigger(stream, false);
>> +	if (ret) {
>> +		dev_err(adev->dev, "transfer lib %d failed: %d\n", id,
>> ret);
>> +		ret = AVS_IPC_RET(ret);
>> +	}
>> +
>> +	/* disable SPIB for hda stream */
>> +	snd_hdac_ext_stream_spbcap_enable(bus, false, stream->index);
>> +	snd_hdac_ext_stream_set_spib(bus, estream, 0);
>> +
>> +	snd_hdac_dsp_cleanup(stream, &dmab);
>> +release_stream:
>> +	snd_hdac_ext_stream_release(estream,
>> HDAC_EXT_STREAM_TYPE_HOST);
>> +
>> +	return ret;
>> +}
>> +
>> +int avs_hda_transfer_modules(struct avs_dev *adev, bool load,
>> +			     struct avs_module_entry *mods, u32
>> num_mods)
> What is the difference between transfer_modules and load_library?


Libraries targeting SKL/KBL/AML platforms *are just manifests* - the 
actual module code is found in the separate file(s) and thus the need 
for separate handlers. The driver has to load both the manifest and the 
module code to have a working streaming scenario requiring module type 
exposed by said library.


Regards,
Czarek

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

* Re: [PATCH v3 17/17] ASoC: Intel: avs: Code loading over HDA
  2022-03-04 18:44     ` Cezary Rojewski
@ 2022-03-04 18:56       ` Pierre-Louis Bossart
  2022-03-07 14:31         ` Cezary Rojewski
  0 siblings, 1 reply; 65+ messages in thread
From: Pierre-Louis Bossart @ 2022-03-04 18:56 UTC (permalink / raw)
  To: Cezary Rojewski, Ranjani Sridharan, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, hdegoede, broonie,
	amadeuszx.slawinski, cujomalainey, lma


>>> Compared to SKL and KBL, younger cAVS platforms are meant to re-use
>>> one
>> Younger? you mean newer?
> 
> 
> Isn't the meaning of the two quite similar in this context?

younger doesn't sound quite right to me.

'cAVS platforms more recent that SKL and KBL...'

> 
>>> of HDAudio streams during boot procedure causing CLDMA to become
>>> obsolete. Once transferred, given stream is returned to pool
>>> available
>>> for audio streaming.
>>>
>>> Module loading handler is dummy as library and module code became
>>> inseparable in later firmware generations.
>> replace dummy with "stub" maybe? lets use inclusive terms
> 
> 
> Is 'dummy' categorized as non-inclusive? We have several usages of 
> 'dummy' even within /sound (e.g. soc-utils.c).

Intel and plenty of other companies recommend a different wording. 
mock-up, stub, placeholder, etc. see e.g.

https://developers.google.com/style/inclusive-documentation

Yes we have plenty of existing uses of 'dummy', but that doesn't mean we 
should add new ones.

>>> +static int
>>> +avs_hda_init_rom(struct avs_dev *adev, unsigned int dma_id, bool
>>> purge)
>>> +{
>>> +    const struct avs_spec *const spec = adev->spec;
>>> +    unsigned int corex_mask, reg;
>>> +    int ret;
>>> +
>>> +    corex_mask = spec->core_init_mask & ~AVS_MAIN_CORE_MASK;
>>> +
>>> +    ret = avs_dsp_op(adev, power, spec->core_init_mask, true);
>>> +    if (ret < 0)
>>> +        goto err;
>>> +
>>> +    ret = avs_dsp_op(adev, reset, AVS_MAIN_CORE_MASK, false);
>>> +    if (ret < 0)
>>> +        goto err;
>>> +
>>> +    reinit_completion(&adev->fw_ready);
>>> +    avs_dsp_op(adev, int_control, true);
>>> +
>>> +    /* set boot config */
>>> +    ret = avs_ipc_set_boot_config(adev, dma_id, purge);
>>> +    if (ret) {
>>> +        ret = AVS_IPC_RET(ret);
>>> +        goto err;
>>> +    }
>>> +
>>> +    /* await ROM init */
>>> +    ret = snd_hdac_adsp_readq_poll(adev, spec->rom_status, reg,
>>> +                       (reg & 0xF) == AVS_ROM_INIT_DONE
>>> ||
>>> +                       (reg & 0xF) ==
>>> APL_ROM_FW_ENTERED,
>>> +                       AVS_ROM_INIT_POLLING_US,
>>> APL_ROM_INIT_TIMEOUT_US);
>>> +    if (ret < 0) {
>>> +        dev_err(adev->dev, "rom init timeout: %d\n", ret);
>>> +        goto err;
>>> +    }
>>> +
>>> +    /* power down non-main cores */
>>> +    if (corex_mask)
>>> +        avs_dsp_op(adev, power, corex_mask, false);
>> What if this fails?
> 
> 
> We are still in happy path, worst thing could happen here is increased 
> power consumption.

'happy path'?


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

* Re: [PATCH v3 17/17] ASoC: Intel: avs: Code loading over HDA
  2022-03-04 18:56       ` Pierre-Louis Bossart
@ 2022-03-07 14:31         ` Cezary Rojewski
  0 siblings, 0 replies; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-07 14:31 UTC (permalink / raw)
  To: Pierre-Louis Bossart, Ranjani Sridharan, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, hdegoede, broonie,
	amadeuszx.slawinski, cujomalainey, lma

On 2022-03-04 7:56 PM, Pierre-Louis Bossart wrote:
> 
>>>> Compared to SKL and KBL, younger cAVS platforms are meant to re-use
>>>> one
>>> Younger? you mean newer?
>>
>>
>> Isn't the meaning of the two quite similar in this context?
> 
> younger doesn't sound quite right to me.
> 
> 'cAVS platforms more recent that SKL and KBL...'


Sure, can reword.

>>>> Module loading handler is dummy as library and module code became
>>>> inseparable in later firmware generations.
>>> replace dummy with "stub" maybe? lets use inclusive terms
>>
>>
>> Is 'dummy' categorized as non-inclusive? We have several usages of 
>> 'dummy' even within /sound (e.g. soc-utils.c).
> 
> Intel and plenty of other companies recommend a different wording. 
> mock-up, stub, placeholder, etc. see e.g.
> 
> https://developers.google.com/style/inclusive-documentation
> 
> Yes we have plenty of existing uses of 'dummy', but that doesn't mean we 
> should add new ones.


No problem with rewording this one in v4.

>>>> +static int
>>>> +avs_hda_init_rom(struct avs_dev *adev, unsigned int dma_id, bool
>>>> purge)
>>>> +{
>>>> +    const struct avs_spec *const spec = adev->spec;
>>>> +    unsigned int corex_mask, reg;
>>>> +    int ret;
>>>> +
>>>> +    corex_mask = spec->core_init_mask & ~AVS_MAIN_CORE_MASK;
>>>> +
>>>> +    ret = avs_dsp_op(adev, power, spec->core_init_mask, true);
>>>> +    if (ret < 0)
>>>> +        goto err;
>>>> +
>>>> +    ret = avs_dsp_op(adev, reset, AVS_MAIN_CORE_MASK, false);
>>>> +    if (ret < 0)
>>>> +        goto err;
>>>> +
>>>> +    reinit_completion(&adev->fw_ready);
>>>> +    avs_dsp_op(adev, int_control, true);
>>>> +
>>>> +    /* set boot config */
>>>> +    ret = avs_ipc_set_boot_config(adev, dma_id, purge);
>>>> +    if (ret) {
>>>> +        ret = AVS_IPC_RET(ret);
>>>> +        goto err;
>>>> +    }
>>>> +
>>>> +    /* await ROM init */
>>>> +    ret = snd_hdac_adsp_readq_poll(adev, spec->rom_status, reg,
>>>> +                       (reg & 0xF) == AVS_ROM_INIT_DONE
>>>> ||
>>>> +                       (reg & 0xF) ==
>>>> APL_ROM_FW_ENTERED,
>>>> +                       AVS_ROM_INIT_POLLING_US,
>>>> APL_ROM_INIT_TIMEOUT_US);
>>>> +    if (ret < 0) {
>>>> +        dev_err(adev->dev, "rom init timeout: %d\n", ret);
>>>> +        goto err;
>>>> +    }
>>>> +
>>>> +    /* power down non-main cores */
>>>> +    if (corex_mask)
>>>> +        avs_dsp_op(adev, power, corex_mask, false);
>>> What if this fails?
>>
>>
>> We are still in happy path, worst thing could happen here is increased 
>> power consumption.
> 
> 'happy path'?

The question is whether we value user experience over error-checking 
this case. I've never seen this step failing and the step itself is 
quite.. extraordinary : ) It's also invoked on very limited number of 
cAVS platforms, for everything else it's just: 'return 0'.


Regards,
Czarek

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

* Re: [PATCH v3 04/17] ASoC: Intel: avs: Inter process communication
  2022-03-04 17:11     ` Cezary Rojewski
@ 2022-03-07 16:15       ` Ranjani Sridharan
  2022-03-07 16:23         ` Cezary Rojewski
  0 siblings, 1 reply; 65+ messages in thread
From: Ranjani Sridharan @ 2022-03-07 16:15 UTC (permalink / raw)
  To: Cezary Rojewski, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

On Fri, 2022-03-04 at 18:11 +0100, Cezary Rojewski wrote:
> > > +     * -EPERM error code is expected and thus it's not an actual
> > > error.
> > And what happens in this case? do you retry the IPC after recovery?
> 
> 
> 
> 
> Not at all. Why would you want retry IPC after recovery in the first
> place?
So what happens after FW recovery? Will this lead to an xrun and cause
usersapce to restart the stream?

Thanks,Ranjani


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

* Re: [PATCH v3 04/17] ASoC: Intel: avs: Inter process communication
  2022-03-07 16:15       ` Ranjani Sridharan
@ 2022-03-07 16:23         ` Cezary Rojewski
  0 siblings, 0 replies; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-07 16:23 UTC (permalink / raw)
  To: Ranjani Sridharan, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

On 2022-03-07 5:15 PM, Ranjani Sridharan wrote:
> On Fri, 2022-03-04 at 18:11 +0100, Cezary Rojewski wrote:
>>>> +     * -EPERM error code is expected and thus it's not an actual
>>>> error.
>>> And what happens in this case? do you retry the IPC after recovery?
>>
>>
>>
>>
>> Not at all. Why would you want retry IPC after recovery in the first
>> place?
> So what happens after FW recovery? Will this lead to an xrun and cause
> usersapce to restart the stream?

If DSP dies so does the stream. Recovery is not guaranteed, it's an 
attempt. What userspace does with that is for userspace to decide.


Regards,
Czarek

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

* Re: [PATCH v3 07/17] ASoC: Intel: avs: Add module management requests
  2022-03-04 17:21     ` Cezary Rojewski
@ 2022-03-07 16:39       ` Ranjani Sridharan
  2022-03-07 16:58         ` Cezary Rojewski
  0 siblings, 1 reply; 65+ messages in thread
From: Ranjani Sridharan @ 2022-03-07 16:39 UTC (permalink / raw)
  To: Cezary Rojewski, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

On Fri, 2022-03-04 at 18:21 +0100, Cezary Rojewski wrote:
> > Are there any rules for unbinding? For example if you have 2
> > modules
> > connected to a mixer? Can you unbind the module belonging to the
> > host
> > pipeline that is getting stopped while the mixer is still active?
> 
> 
> 
> 
> Here we have just a delegate. All the rules are defined and enforced
> by 
> 
> the firmware.
I'm not following this, Czarek. If there are rules defined by the FW,
the driver has to follow it isnt it? What I am asking is how and where
do you enforce this in the AVS driver?

...
> > > 
> > How come you dont have a loop here? What if the rec'd data size if
> > larger than the max size of IP payload?
> 
> 
> 
> 
> That's not how LARGE_CONFIG_GET message works. There is no looping 
> 
> involved or expected by the firmware and so we don't have it here.

So, are you saying that when retrieving data from the FW, the size of
the retrieved data can never exceed max IPC payload size?

Thanks,Ranjani


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

* Re: [PATCH v3 10/17] ASoC: Intel: avs: Add basefw runtime-parameter requests
  2022-03-04 17:37     ` Cezary Rojewski
@ 2022-03-07 16:41       ` Ranjani Sridharan
  2022-03-07 17:02         ` Cezary Rojewski
  0 siblings, 1 reply; 65+ messages in thread
From: Ranjani Sridharan @ 2022-03-07 16:41 UTC (permalink / raw)
  To: Cezary Rojewski, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

> > > +	kfree(payload);
> > I think it would be easier to understand this kfree if payload was
> > also
> > allocated in this function in stead of inside the
> > get_large_config().
> 
> That's a good thinking. There was an internal conversation regarding 
> this back in time when we have been implementing getters for the
> first 
> time. There are no clear victors, there are drawbacks - as you do
> not 
> know the size upfront, caller has to guess and then reallocate the 
> buffer accordingly to retrieved payload size from the firmware. So,
> even 
> if you allocate buffer here, chances are, it's not the same buffer
> when 
> the avs_ipc_get_large_config() returns to the caller.
> 
> We have decided to reduce the code size by letting the single,
> common 
> handler do the allocation and leave the other responsibilities to
> the 
> caller.

What could make it simpler is if you allocate MAX IPC size for payload
in this function and then copy the right size in the
avs_ipc_get_large_config(). payload_size tells you that information
anyway right?

Thanks,
Ranjani


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

* Re: [PATCH v3 11/17] ASoC: Intel: avs: Firmware resources management utilities
  2022-03-04 18:02     ` Cezary Rojewski
@ 2022-03-07 16:46       ` Ranjani Sridharan
  2022-03-07 17:13         ` Cezary Rojewski
  0 siblings, 1 reply; 65+ messages in thread
From: Ranjani Sridharan @ 2022-03-07 16:46 UTC (permalink / raw)
  To: Cezary Rojewski, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

> > > + * @modres_mutex: For synchronizing any @mods_info updates
> > Is this mutex really necessary? Can you please elaborate under what
> > circumstances your will have parallel module updates?
> 
> 
> 
> 
> Yes, we believe modres_mutex is necessary. All information regarding 
> 
> modules exposed by the firmware are stored within ->mods_info cache.
> 
> 
> 
> That's just a snapshot though. When a new library gets loaded, new 
> 
> modules may be available for use and so the driver updates the 
> 
> ->mods_info cache to have the latest snapshot. As information found 
> 
> there is used when streaming (e.g.: instantiating modules), we enter
> a 
> 
> scenario when multiple threads could be reading/updating the
> ->mods_info 
> 
> at once. To prevent any unwanted behavior, mutex has been added.
This is the part that's hard to follow without seeing the actual code
where this new library is loaded. When does a libray get loaded? When
you start streaming and you realize that the stream requires a module
that is not built into the base FW? Can this be done during topology
loading instead?

Thanks,
Rnajani


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

* Re: [PATCH v3 07/17] ASoC: Intel: avs: Add module management requests
  2022-03-07 16:39       ` Ranjani Sridharan
@ 2022-03-07 16:58         ` Cezary Rojewski
  2022-03-07 17:05           ` Ranjani Sridharan
  0 siblings, 1 reply; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-07 16:58 UTC (permalink / raw)
  To: Ranjani Sridharan, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

On 2022-03-07 5:39 PM, Ranjani Sridharan wrote:
> On Fri, 2022-03-04 at 18:21 +0100, Cezary Rojewski wrote:
>>> Are there any rules for unbinding? For example if you have 2
>>> modules
>>> connected to a mixer? Can you unbind the module belonging to the
>>> host
>>> pipeline that is getting stopped while the mixer is still active?
>>
>>
>>
>>
>> Here we have just a delegate. All the rules are defined and enforced
>> by
>>
>> the firmware.
> I'm not following this, Czarek. If there are rules defined by the FW,
> the driver has to follow it isnt it? What I am asking is how and where
> do you enforce this in the AVS driver?


How the stream looks is defined by the topology. Code that translates 
such patterns into runtime being is not part of this patchset. It's part 
of avs_path and its collaterals instead.

>>>>
>>> How come you dont have a loop here? What if the rec'd data size if
>>> larger than the max size of IP payload?
>>
>>
>>
>>
>> That's not how LARGE_CONFIG_GET message works. There is no looping
>>
>> involved or expected by the firmware and so we don't have it here.
> 
> So, are you saying that when retrieving data from the FW, the size of
> the retrieved data can never exceed max IPC payload size?


Precisely.

Regards,
Czarek

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

* Re: [PATCH v3 10/17] ASoC: Intel: avs: Add basefw runtime-parameter requests
  2022-03-07 16:41       ` Ranjani Sridharan
@ 2022-03-07 17:02         ` Cezary Rojewski
  2022-03-07 17:06           ` Ranjani Sridharan
  0 siblings, 1 reply; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-07 17:02 UTC (permalink / raw)
  To: Ranjani Sridharan, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

On 2022-03-07 5:41 PM, Ranjani Sridharan wrote:
>>>> +	kfree(payload);
>>> I think it would be easier to understand this kfree if payload was
>>> also
>>> allocated in this function in stead of inside the
>>> get_large_config().
>>
>> That's a good thinking. There was an internal conversation regarding
>> this back in time when we have been implementing getters for the
>> first
>> time. There are no clear victors, there are drawbacks - as you do
>> not
>> know the size upfront, caller has to guess and then reallocate the
>> buffer accordingly to retrieved payload size from the firmware. So,
>> even
>> if you allocate buffer here, chances are, it's not the same buffer
>> when
>> the avs_ipc_get_large_config() returns to the caller.
>>
>> We have decided to reduce the code size by letting the single,
>> common
>> handler do the allocation and leave the other responsibilities to
>> the
>> caller.
> 
> What could make it simpler is if you allocate MAX IPC size for payload
> in this function and then copy the right size in the
> avs_ipc_get_large_config(). payload_size tells you that information
> anyway right?


As stated, there is no clear winner here - you had to repeat such code 
for every getter.

Since we are getting payload_size already, retrieving payload itself is 
just fine.


Regards,
Czarek

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

* Re: [PATCH v3 07/17] ASoC: Intel: avs: Add module management requests
  2022-03-07 16:58         ` Cezary Rojewski
@ 2022-03-07 17:05           ` Ranjani Sridharan
  2022-03-07 17:27             ` Cezary Rojewski
  0 siblings, 1 reply; 65+ messages in thread
From: Ranjani Sridharan @ 2022-03-07 17:05 UTC (permalink / raw)
  To: Cezary Rojewski, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

On Mon, 2022-03-07 at 17:58 +0100, Cezary Rojewski wrote:
> > I'm not following this, Czarek. If there are rules defined by the
> > FW,
> > the driver has to follow it isnt it? What I am asking is how and
> > where
> > do you enforce this in the AVS driver?
> 
> 
> 
> 
> How the stream looks is defined by the topology. Code that
> translates 
> 
> such patterns into runtime being is not part of this patchset. It's
> part 
> 
> of avs_path and its collaterals instead.
Alright, I'll wait for the next patchset for the explanation.

> 
> 
> 
> > > > How come you dont have a loop here? What if the rec'd data size
> > > > if
> > > > larger than the max size of IP payload?
> > > That's not how LARGE_CONFIG_GET message works. There is no
> > > looping
> > > involved or expected by the firmware and so we don't have it
> > > here.
> > So, are you saying that when retrieving data from the FW, the size
> > of
> > the retrieved data can never exceed max IPC payload size?
> 
> 
> 
> 
> Precisely.
This is fundmentally flawed isnt it? If set_large_config() sets a
config that can exceed max IPC size, get_large_config() has to be able
to support it.

Thanks,
Ranjani


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

* Re: [PATCH v3 10/17] ASoC: Intel: avs: Add basefw runtime-parameter requests
  2022-03-07 17:02         ` Cezary Rojewski
@ 2022-03-07 17:06           ` Ranjani Sridharan
  2022-03-07 17:28             ` Cezary Rojewski
  0 siblings, 1 reply; 65+ messages in thread
From: Ranjani Sridharan @ 2022-03-07 17:06 UTC (permalink / raw)
  To: Cezary Rojewski, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

On Mon, 2022-03-07 at 18:02 +0100, Cezary Rojewski wrote:
> > What could make it simpler is if you allocate MAX IPC size for
> > payload
> > in this function and then copy the right size in the
> > avs_ipc_get_large_config(). payload_size tells you that information
> > anyway right?
> 
> 
> 
> 
> As stated, there is no clear winner here - you had to repeat such
> code 
> 
> for every getter.
> 
> 
> 
> Since we are getting payload_size already, retrieving payload itself
> is 
> 
> just fine.

OK, can you please add a comment to state this in the patch so the
reviewer doesnt have to track down where this memory is allocated?

Thanks,Ranjani


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

* Re: [PATCH v3 11/17] ASoC: Intel: avs: Firmware resources management utilities
  2022-03-07 16:46       ` Ranjani Sridharan
@ 2022-03-07 17:13         ` Cezary Rojewski
  2022-03-07 17:30           ` Ranjani Sridharan
  0 siblings, 1 reply; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-07 17:13 UTC (permalink / raw)
  To: Ranjani Sridharan, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

On 2022-03-07 5:46 PM, Ranjani Sridharan wrote:
>>>> + * @modres_mutex: For synchronizing any @mods_info updates
>>> Is this mutex really necessary? Can you please elaborate under what
>>> circumstances your will have parallel module updates?
>>
>>
>>
>>
>> Yes, we believe modres_mutex is necessary. All information regarding
>>
>> modules exposed by the firmware are stored within ->mods_info cache.
>>
>>
>>
>> That's just a snapshot though. When a new library gets loaded, new
>>
>> modules may be available for use and so the driver updates the
>>
>> ->mods_info cache to have the latest snapshot. As information found
>>
>> there is used when streaming (e.g.: instantiating modules), we enter
>> a
>>
>> scenario when multiple threads could be reading/updating the
>> ->mods_info
>>
>> at once. To prevent any unwanted behavior, mutex has been added.
> This is the part that's hard to follow without seeing the actual code
> where this new library is loaded. When does a libray get loaded? When
> you start streaming and you realize that the stream requires a module
> that is not built into the base FW? Can this be done during topology
> loading instead?

But that's already done during topology load! If there is no topology 
telling the driver: "hey, load this lib for me!", nothing gets loaded 
regardless of how your /lib/firmware looks like. Libraries get loaded 
during soc-component's (platform component) ->probe(). This is place 
where snd_soc_tplg_component_load() is called.

However, if platform has no IMR capability, driver has to re-load 
libraries for all platform components of bound sound cards on every 
pm_runtime_resume().


Regards,
Czarek

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

* Re: [PATCH v3 07/17] ASoC: Intel: avs: Add module management requests
  2022-03-07 17:05           ` Ranjani Sridharan
@ 2022-03-07 17:27             ` Cezary Rojewski
  2022-03-07 17:47               ` Pierre-Louis Bossart
  0 siblings, 1 reply; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-07 17:27 UTC (permalink / raw)
  To: Ranjani Sridharan, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

On 2022-03-07 6:05 PM, Ranjani Sridharan wrote:
> On Mon, 2022-03-07 at 17:58 +0100, Cezary Rojewski wrote:
>>> I'm not following this, Czarek. If there are rules defined by the
>>> FW,
>>> the driver has to follow it isnt it? What I am asking is how and
>>> where
>>> do you enforce this in the AVS driver?
>>
>>
>>
>>
>> How the stream looks is defined by the topology. Code that
>> translates
>>
>> such patterns into runtime being is not part of this patchset. It's
>> part
>>
>> of avs_path and its collaterals instead.
> Alright, I'll wait for the next patchset for the explanation.
> 
>>
>>
>>
>>>>> How come you dont have a loop here? What if the rec'd data size
>>>>> if
>>>>> larger than the max size of IP payload?
>>>> That's not how LARGE_CONFIG_GET message works. There is no
>>>> looping
>>>> involved or expected by the firmware and so we don't have it
>>>> here.
>>> So, are you saying that when retrieving data from the FW, the size
>>> of
>>> the retrieved data can never exceed max IPC payload size?
>>
>>
>>
>>
>> Precisely.
> This is fundmentally flawed isnt it? If set_large_config() sets a
> config that can exceed max IPC size, get_large_config() has to be able
> to support it.

I could ask people on the list to "not look for a second" then there 
would be no problem explaining all the *recommended flows*.

Simple, honest answer is: Yes, that's fundamentally flawed.
Now, as older firmware generations do not expect nor support larger 
payload sizes, adding such code here is essentially adding dead code so 
we have decided to add none of it.


Regards,
Czarek

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

* Re: [PATCH v3 10/17] ASoC: Intel: avs: Add basefw runtime-parameter requests
  2022-03-07 17:06           ` Ranjani Sridharan
@ 2022-03-07 17:28             ` Cezary Rojewski
  0 siblings, 0 replies; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-07 17:28 UTC (permalink / raw)
  To: Ranjani Sridharan, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

On 2022-03-07 6:06 PM, Ranjani Sridharan wrote:
> On Mon, 2022-03-07 at 18:02 +0100, Cezary Rojewski wrote:
>>> What could make it simpler is if you allocate MAX IPC size for
>>> payload
>>> in this function and then copy the right size in the
>>> avs_ipc_get_large_config(). payload_size tells you that information
>>> anyway right?
>>
>>
>>
>>
>> As stated, there is no clear winner here - you had to repeat such
>> code
>>
>> for every getter.
>>
>>
>>
>> Since we are getting payload_size already, retrieving payload itself
>> is
>>
>> just fine.
> 
> OK, can you please add a comment to state this in the patch so the
> reviewer doesnt have to track down where this memory is allocated?


Sure, will add in v4.

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

* Re: [PATCH v3 11/17] ASoC: Intel: avs: Firmware resources management utilities
  2022-03-07 17:13         ` Cezary Rojewski
@ 2022-03-07 17:30           ` Ranjani Sridharan
  2022-03-08 16:57             ` Cezary Rojewski
  0 siblings, 1 reply; 65+ messages in thread
From: Ranjani Sridharan @ 2022-03-07 17:30 UTC (permalink / raw)
  To: Cezary Rojewski, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

On Mon, 2022-03-07 at 18:13 +0100, Cezary Rojewski wrote:
> > This is the part that's hard to follow without seeing the actual
> > code
> > where this new library is loaded. When does a libray get loaded?
> > When
> > you start streaming and you realize that the stream requires a
> > module
> > that is not built into the base FW? Can this be done during
> > topology
> > loading instead?
> 
> 
> But that's already done during topology load! If there is no
> topology 
> 
> telling the driver: "hey, load this lib for me!", nothing gets
> loaded 
> 
> regardless of how your /lib/firmware looks like. Libraries get
> loaded 
> 
> during soc-component's (platform component) ->probe(). This is place 
> 
> where snd_soc_tplg_component_load() is called.
> 
> 
> 
> However, if platform has no IMR capability, driver has to re-load 
> 
> libraries for all platform components of bound sound cards on every 
> 
> pm_runtime_resume().

And if it done during pm_runtime_resume(), where would the problem with
synchronizing arise from? userspace apps do not get resumed until after
the PCI device is resumed isnt it?

Thanks,
Ranjani


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

* Re: [PATCH v3 07/17] ASoC: Intel: avs: Add module management requests
  2022-03-07 17:27             ` Cezary Rojewski
@ 2022-03-07 17:47               ` Pierre-Louis Bossart
  0 siblings, 0 replies; 65+ messages in thread
From: Pierre-Louis Bossart @ 2022-03-07 17:47 UTC (permalink / raw)
  To: Cezary Rojewski, Ranjani Sridharan, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, hdegoede, broonie,
	amadeuszx.slawinski, cujomalainey, lma



>>>>>> How come you dont have a loop here? What if the rec'd data size
>>>>>> if
>>>>>> larger than the max size of IP payload?
>>>>> That's not how LARGE_CONFIG_GET message works. There is no
>>>>> looping
>>>>> involved or expected by the firmware and so we don't have it
>>>>> here.
>>>> So, are you saying that when retrieving data from the FW, the size
>>>> of
>>>> the retrieved data can never exceed max IPC payload size?
>>>
>>>
>>>
>>>
>>> Precisely.
>> This is fundmentally flawed isnt it? If set_large_config() sets a
>> config that can exceed max IPC size, get_large_config() has to be able
>> to support it.
> 
> I could ask people on the list to "not look for a second" then there 
> would be no problem explaining all the *recommended flows*.
> 
> Simple, honest answer is: Yes, that's fundamentally flawed.
> Now, as older firmware generations do not expect nor support larger 
> payload sizes, adding such code here is essentially adding dead code so 
> we have decided to add none of it.

Adding a comment and/or an explanation in the commit message wouldn't 
hurt then.

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

* Re: [PATCH v3 11/17] ASoC: Intel: avs: Firmware resources management utilities
  2022-03-07 17:30           ` Ranjani Sridharan
@ 2022-03-08 16:57             ` Cezary Rojewski
  2022-03-08 17:22               ` Ranjani Sridharan
  0 siblings, 1 reply; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-08 16:57 UTC (permalink / raw)
  To: Ranjani Sridharan, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

On 2022-03-07 6:30 PM, Ranjani Sridharan wrote:
> On Mon, 2022-03-07 at 18:13 +0100, Cezary Rojewski wrote:
>>> This is the part that's hard to follow without seeing the actual
>>> code
>>> where this new library is loaded. When does a libray get loaded?
>>> When
>>> you start streaming and you realize that the stream requires a
>>> module
>>> that is not built into the base FW? Can this be done during
>>> topology
>>> loading instead?
>>
>>
>> But that's already done during topology load! If there is no
>> topology
>>
>> telling the driver: "hey, load this lib for me!", nothing gets
>> loaded
>>
>> regardless of how your /lib/firmware looks like. Libraries get
>> loaded
>>
>> during soc-component's (platform component) ->probe(). This is place
>>
>> where snd_soc_tplg_component_load() is called.
>>
>>
>>
>> However, if platform has no IMR capability, driver has to re-load
>>
>> libraries for all platform components of bound sound cards on every
>>
>> pm_runtime_resume().
> 
> And if it done during pm_runtime_resume(), where would the problem with
> synchronizing arise from? userspace apps do not get resumed until after
> the PCI device is resumed isnt it?

Scenario you describe is correct and does not prompt the need for the mutex.

However, ->mods_info is accessed through getters found in utils.c (this 
very patch) during stream creation too. That fragment is part of path 
management series though - it was requested to split those bits away.

So, there is a possibility for a platform-soc-component to have its 
->probe() called - and thus triggering ->mods_info update - while a 
stream is being opened on a different sound card simultaneously. To 
avoid unwanted behavior e.g.: looping through ->mods_info while it's 
being updated in separate thread, we lock the array.


Regards,
Czarek

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

* Re: [PATCH v3 11/17] ASoC: Intel: avs: Firmware resources management utilities
  2022-03-08 16:57             ` Cezary Rojewski
@ 2022-03-08 17:22               ` Ranjani Sridharan
  2022-03-08 18:07                 ` Cezary Rojewski
  0 siblings, 1 reply; 65+ messages in thread
From: Ranjani Sridharan @ 2022-03-08 17:22 UTC (permalink / raw)
  To: Cezary Rojewski, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

On Tue, 2022-03-08 at 17:57 +0100, Cezary Rojewski wrote:
> Scenario you describe is correct and does not prompt the need for the
> mutex.
> 
> 
> 
> However, ->mods_info is accessed through getters found in utils.c
> (this 
> 
> very patch) during stream creation too. That fragment is part of
> path 
> 
> management series though - it was requested to split those bits away.
> 
> 
> 
> So, there is a possibility for a platform-soc-component to have its 
> 
> ->probe() called - and thus triggering ->mods_info update - while a 
> 
> stream is being opened on a different sound card simultaneously. To 
> 
> avoid unwanted behavior e.g.: looping through ->mods_info while it's 
> 
> being updated in separate thread, we lock the array.

Keeping in mind that this driver is meant for older platforms, how
likely are you to support multiple sound cards with those topologies?

Thanks,
Ranjani


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

* Re: [PATCH v3 11/17] ASoC: Intel: avs: Firmware resources management utilities
  2022-03-08 17:22               ` Ranjani Sridharan
@ 2022-03-08 18:07                 ` Cezary Rojewski
  2022-03-08 18:26                   ` Ranjani Sridharan
  0 siblings, 1 reply; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-08 18:07 UTC (permalink / raw)
  To: Ranjani Sridharan, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

On 2022-03-08 6:22 PM, Ranjani Sridharan wrote:
> On Tue, 2022-03-08 at 17:57 +0100, Cezary Rojewski wrote:
>> Scenario you describe is correct and does not prompt the need for the
>> mutex.
>>
>>
>>
>> However, ->mods_info is accessed through getters found in utils.c
>> (this
>>
>> very patch) during stream creation too. That fragment is part of
>> path
>>
>> management series though - it was requested to split those bits away.
>>
>>
>>
>> So, there is a possibility for a platform-soc-component to have its
>>
>> ->probe() called - and thus triggering ->mods_info update - while a
>>
>> stream is being opened on a different sound card simultaneously. To
>>
>> avoid unwanted behavior e.g.: looping through ->mods_info while it's
>>
>> being updated in separate thread, we lock the array.
> 
> Keeping in mind that this driver is meant for older platforms, how
> likely are you to support multiple sound cards with those topologies?

Not sure what's the question here. Age of the platform has nothing to do 
with the subject. There is not a single DSP-capable platform that Intel 
has shipped that would not contain more one audio device onboard. At 
least I'm not aware of any.


Regards,
Czarek

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

* Re: [PATCH v3 11/17] ASoC: Intel: avs: Firmware resources management utilities
  2022-03-08 18:07                 ` Cezary Rojewski
@ 2022-03-08 18:26                   ` Ranjani Sridharan
  2022-03-08 18:31                     ` Cezary Rojewski
  0 siblings, 1 reply; 65+ messages in thread
From: Ranjani Sridharan @ 2022-03-08 18:26 UTC (permalink / raw)
  To: Cezary Rojewski, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

On Tue, 2022-03-08 at 19:07 +0100, Cezary Rojewski wrote:
> > Keeping in mind that this driver is meant for older platforms, how
> > likely are you to support multiple sound cards with those
> > topologies?
> 
> 
> Not sure what's the question here. Age of the platform has nothing to
> do 
> 
> with the subject. There is not a single DSP-capable platform that
> Intel 
> 
> has shipped that would not contain more one audio device onboard. At 
> 
> least I'm not aware of any.

My question was related to your comment about multiple sound cards.
What I asked was do you plan to support multiple topologies with
modules spread across then with multiple sound component drivers with
the AVS driver and firmware? Does this mean you will need multiple
topology files and machine driver? And what is the rationale for this?

If not, there's no need for the mutex.

Thanks,
Ranjani


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

* Re: [PATCH v3 11/17] ASoC: Intel: avs: Firmware resources management utilities
  2022-03-08 18:26                   ` Ranjani Sridharan
@ 2022-03-08 18:31                     ` Cezary Rojewski
  2022-03-08 19:42                       ` Pierre-Louis Bossart
  0 siblings, 1 reply; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-08 18:31 UTC (permalink / raw)
  To: Ranjani Sridharan, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, pierre-louis.bossart,
	hdegoede, broonie, amadeuszx.slawinski, cujomalainey, lma

On 2022-03-08 7:26 PM, Ranjani Sridharan wrote:
> On Tue, 2022-03-08 at 19:07 +0100, Cezary Rojewski wrote:
>>> Keeping in mind that this driver is meant for older platforms, how
>>> likely are you to support multiple sound cards with those
>>> topologies?
>>
>>
>> Not sure what's the question here. Age of the platform has nothing to
>> do
>>
>> with the subject. There is not a single DSP-capable platform that
>> Intel
>>
>> has shipped that would not contain more one audio device onboard. At
>>
>> least I'm not aware of any.
> 
> My question was related to your comment about multiple sound cards.
> What I asked was do you plan to support multiple topologies with
> modules spread across then with multiple sound component drivers with
> the AVS driver and firmware? Does this mean you will need multiple
> topology files and machine driver? And what is the rationale for this?
> 
> If not, there's no need for the mutex.

Yes, avs-driver embraces granular sound card approach as opposed to 
super card approach. There is one topology file per sound card.

That subject is not part of this patchset though.


Regards,
Czarek

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

* Re: [PATCH v3 11/17] ASoC: Intel: avs: Firmware resources management utilities
  2022-03-08 18:31                     ` Cezary Rojewski
@ 2022-03-08 19:42                       ` Pierre-Louis Bossart
  2022-03-09 17:23                         ` Cezary Rojewski
  0 siblings, 1 reply; 65+ messages in thread
From: Pierre-Louis Bossart @ 2022-03-08 19:42 UTC (permalink / raw)
  To: Cezary Rojewski, Ranjani Sridharan, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, hdegoede, broonie,
	amadeuszx.slawinski, cujomalainey, lma



On 3/8/22 12:31, Cezary Rojewski wrote:
> On 2022-03-08 7:26 PM, Ranjani Sridharan wrote:
>> On Tue, 2022-03-08 at 19:07 +0100, Cezary Rojewski wrote:
>>>> Keeping in mind that this driver is meant for older platforms, how
>>>> likely are you to support multiple sound cards with those
>>>> topologies?
>>>
>>>
>>> Not sure what's the question here. Age of the platform has nothing to
>>> do
>>>
>>> with the subject. There is not a single DSP-capable platform that
>>> Intel
>>>
>>> has shipped that would not contain more one audio device onboard. At
>>>
>>> least I'm not aware of any.
>>
>> My question was related to your comment about multiple sound cards.
>> What I asked was do you plan to support multiple topologies with
>> modules spread across then with multiple sound component drivers with
>> the AVS driver and firmware? Does this mean you will need multiple
>> topology files and machine driver? And what is the rationale for this?
>>
>> If not, there's no need for the mutex.
> 
> Yes, avs-driver embraces granular sound card approach as opposed to 
> super card approach. There is one topology file per sound card.
> 
> That subject is not part of this patchset though.

You would still need to clarify how the same set of modules might be 
accessed or configured when different cards are created, or if there is 
a 'clean' split with a 1:1 mapping between module and cards.

The more I think of this the less practical this 'granular' approach 
looks, e.g. if you want to route the same stream to different interfaces 
handled by different cards. An example is playing a notification on 
local speakers controlled by HDaudio and a Bluetooth headset using I2S. 
This could be really fun to represent even basic volume control to 
users: controls are card-specific and some parts may be handled in 
different cards and thus different UCM files.

I really think the best split of a DSP topology is between orthogonal 
parts. When muxers/demux are used, or multi-input modules such as AEC, 
the routing complexity outweighs the benefits of a simpler card design.



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

* Re: [PATCH v3 11/17] ASoC: Intel: avs: Firmware resources management utilities
  2022-03-08 19:42                       ` Pierre-Louis Bossart
@ 2022-03-09 17:23                         ` Cezary Rojewski
  0 siblings, 0 replies; 65+ messages in thread
From: Cezary Rojewski @ 2022-03-09 17:23 UTC (permalink / raw)
  To: Pierre-Louis Bossart, Ranjani Sridharan, alsa-devel
  Cc: upstream, harshapriya.n, rad, tiwai, hdegoede, broonie,
	amadeuszx.slawinski, cujomalainey, lma

On 2022-03-08 8:42 PM, Pierre-Louis Bossart wrote:
> On 3/8/22 12:31, Cezary Rojewski wrote:

...

>> Yes, avs-driver embraces granular sound card approach as opposed to 
>> super card approach. There is one topology file per sound card.
>>
>> That subject is not part of this patchset though.
> 
> You would still need to clarify how the same set of modules might be 
> accessed or configured when different cards are created, or if there is 
> a 'clean' split with a 1:1 mapping between module and cards.
> 
> The more I think of this the less practical this 'granular' approach 
> looks, e.g. if you want to route the same stream to different interfaces 
> handled by different cards. An example is playing a notification on 
> local speakers controlled by HDaudio and a Bluetooth headset using I2S. 
> This could be really fun to represent even basic volume control to 
> users: controls are card-specific and some parts may be handled in 
> different cards and thus different UCM files.
> 
> I really think the best split of a DSP topology is between orthogonal 
> parts. When muxers/demux are used, or multi-input modules such as AEC, 
> the routing complexity outweighs the benefits of a simpler card design.

There is a clean split - for all the typical scenarios, topology tied to 
given sound card defines the stream patterns completely.

Even when considering "functional" split as you mention in third 
paragraph, multiple sound cards are still there. So, as I have described 
earlier, to prevent any unwanted behaviour, cached module information in 
form of ->mods_info, is being locked with help of a mutex. We do not 
duplicate such information per sound card as that would be a waste of 
memory. No matter how many libraries are mentioned by the topology files 
and loaded throughout the lifetime of a driver, there is always just one 
base firmware we sent MODULE_INFO to.

In regard to advanced scenarios and more complex routing, it would be 
good to have that conversation as a part of dedicated patchset which is 
going to follow this one (sooner or later).


Regards,
Czarek

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

end of thread, other threads:[~2022-03-09 17:25 UTC | newest]

Thread overview: 65+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-04 14:57 [PATCH v3 00/17] ASoC: Intel: AVS - Audio DSP for cAVS Cezary Rojewski
2022-03-04 14:57 ` [PATCH v3 01/17] ALSA: hda: Add helper macros for DSP capable devices Cezary Rojewski
2022-03-04 14:57 ` [PATCH v3 02/17] ASoC: Export DAI register and widget ctor and dctor functions Cezary Rojewski
2022-03-04 14:57 ` [PATCH v3 03/17] ASoC: Intel: Introduce AVS driver Cezary Rojewski
2022-03-04 15:51   ` Ranjani Sridharan
2022-03-04 16:43     ` Cezary Rojewski
2022-03-04 14:57 ` [PATCH v3 04/17] ASoC: Intel: avs: Inter process communication Cezary Rojewski
2022-03-04 16:09   ` Ranjani Sridharan
2022-03-04 17:11     ` Cezary Rojewski
2022-03-07 16:15       ` Ranjani Sridharan
2022-03-07 16:23         ` Cezary Rojewski
2022-03-04 14:57 ` [PATCH v3 05/17] ASoC: Intel: avs: Add code loading requests Cezary Rojewski
2022-03-04 14:57 ` [PATCH v3 06/17] ASoC: Intel: avs: Add pipeline management requests Cezary Rojewski
2022-03-04 16:13   ` Ranjani Sridharan
2022-03-04 17:15     ` Cezary Rojewski
2022-03-04 14:57 ` [PATCH v3 07/17] ASoC: Intel: avs: Add module " Cezary Rojewski
2022-03-04 16:21   ` Ranjani Sridharan
2022-03-04 17:21     ` Cezary Rojewski
2022-03-07 16:39       ` Ranjani Sridharan
2022-03-07 16:58         ` Cezary Rojewski
2022-03-07 17:05           ` Ranjani Sridharan
2022-03-07 17:27             ` Cezary Rojewski
2022-03-07 17:47               ` Pierre-Louis Bossart
2022-03-04 14:57 ` [PATCH v3 08/17] ASoC: Intel: avs: Add power " Cezary Rojewski
2022-03-04 16:24   ` Ranjani Sridharan
2022-03-04 17:30     ` Cezary Rojewski
2022-03-04 14:57 ` [PATCH v3 09/17] ASoC: Intel: avs: Add ROM requests Cezary Rojewski
2022-03-04 16:26   ` Ranjani Sridharan
2022-03-04 17:33     ` Cezary Rojewski
2022-03-04 14:57 ` [PATCH v3 10/17] ASoC: Intel: avs: Add basefw runtime-parameter requests Cezary Rojewski
2022-03-04 16:31   ` Ranjani Sridharan
2022-03-04 17:37     ` Cezary Rojewski
2022-03-07 16:41       ` Ranjani Sridharan
2022-03-07 17:02         ` Cezary Rojewski
2022-03-07 17:06           ` Ranjani Sridharan
2022-03-07 17:28             ` Cezary Rojewski
2022-03-04 14:57 ` [PATCH v3 11/17] ASoC: Intel: avs: Firmware resources management utilities Cezary Rojewski
2022-03-04 16:41   ` Ranjani Sridharan
2022-03-04 18:02     ` Cezary Rojewski
2022-03-07 16:46       ` Ranjani Sridharan
2022-03-07 17:13         ` Cezary Rojewski
2022-03-07 17:30           ` Ranjani Sridharan
2022-03-08 16:57             ` Cezary Rojewski
2022-03-08 17:22               ` Ranjani Sridharan
2022-03-08 18:07                 ` Cezary Rojewski
2022-03-08 18:26                   ` Ranjani Sridharan
2022-03-08 18:31                     ` Cezary Rojewski
2022-03-08 19:42                       ` Pierre-Louis Bossart
2022-03-09 17:23                         ` Cezary Rojewski
2022-03-04 14:57 ` [PATCH v3 12/17] ASoC: Intel: avs: Declare module configuration types Cezary Rojewski
2022-03-04 16:43   ` Ranjani Sridharan
2022-03-04 18:10     ` Cezary Rojewski
2022-03-04 14:57 ` [PATCH v3 13/17] ASoC: Intel: avs: Dynamic firmware resources management Cezary Rojewski
2022-03-04 16:47   ` Ranjani Sridharan
2022-03-04 18:15     ` Cezary Rojewski
2022-03-04 14:57 ` [PATCH v3 14/17] ASoC: Intel: avs: General code loading flow Cezary Rojewski
2022-03-04 16:54   ` Ranjani Sridharan
2022-03-04 18:29     ` Cezary Rojewski
2022-03-04 14:57 ` [PATCH v3 15/17] ASoC: Intel: avs: Implement CLDMA transfer Cezary Rojewski
2022-03-04 14:57 ` [PATCH v3 16/17] ASoC: Intel: avs: Code loading over CLDMA Cezary Rojewski
2022-03-04 14:57 ` [PATCH v3 17/17] ASoC: Intel: avs: Code loading over HDA Cezary Rojewski
2022-03-04 16:59   ` Ranjani Sridharan
2022-03-04 18:44     ` Cezary Rojewski
2022-03-04 18:56       ` Pierre-Louis Bossart
2022-03-07 14:31         ` Cezary Rojewski

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.