Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ASoC: Intel: avs: Probe compress operations

Add compress operations handlers for data extraction through probes. A
single HDAudio stream is enlisted for said purpose. Operations follow
same protocol as for standard PCM streaming on HOST side.

Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
Link: https://lore.kernel.org/r/20221202152841.672536-11-cezary.rojewski@intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Cezary Rojewski and committed by
Mark Brown
700462f5 dab8d000

+225 -3
+1
sound/soc/intel/Kconfig
··· 217 217 select SND_SOC_ACPI if ACPI 218 218 select SND_SOC_TOPOLOGY 219 219 select SND_SOC_HDA 220 + select SND_SOC_COMPRESS if DEBUG_FS 220 221 select SND_HDA_EXT_CORE 221 222 select SND_HDA_DSP_LOADER 222 223 select SND_INTEL_DSP_CONFIG
+3
sound/soc/intel/avs/avs.h
··· 144 144 u32 aging_timer_period; 145 145 u32 fifo_full_timer_period; 146 146 u32 logged_resources; /* context dependent: core or library */ 147 + /* probes */ 148 + struct hdac_ext_stream *extractor; 149 + unsigned int num_probe_streams; 147 150 #endif 148 151 }; 149 152
+221 -3
sound/soc/intel/avs/probes.c
··· 6 6 // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> 7 7 // 8 8 9 + #include <sound/compress_driver.h> 10 + #include <sound/hdaudio_ext.h> 11 + #include <sound/hdaudio.h> 12 + #include <sound/soc.h> 9 13 #include "avs.h" 10 14 #include "messages.h" 11 15 12 - __maybe_unused 13 16 static int avs_dsp_init_probe(struct avs_dev *adev, union avs_connector_node_id node_id, 14 17 size_t buffer_size) 15 - 16 18 { 17 19 struct avs_probe_cfg cfg = {{0}}; 18 20 struct avs_module_entry mentry; ··· 36 34 sizeof(cfg), &dummy); 37 35 } 38 36 39 - __maybe_unused 40 37 static void avs_dsp_delete_probe(struct avs_dev *adev) 41 38 { 42 39 struct avs_module_entry mentry; ··· 45 44 /* There is only ever one probe module instance. */ 46 45 avs_dsp_delete_module(adev, mentry.module_id, 0, INVALID_PIPELINE_ID, 0); 47 46 } 47 + 48 + static inline struct hdac_ext_stream *avs_compr_get_host_stream(struct snd_compr_stream *cstream) 49 + { 50 + return cstream->runtime->private_data; 51 + } 52 + 53 + static int avs_probe_compr_open(struct snd_compr_stream *cstream, struct snd_soc_dai *dai) 54 + { 55 + struct avs_dev *adev = to_avs_dev(dai->dev); 56 + struct hdac_bus *bus = &adev->base.core; 57 + struct hdac_ext_stream *host_stream; 58 + 59 + if (adev->extractor) { 60 + dev_err(dai->dev, "Cannot open more than one extractor stream\n"); 61 + return -EEXIST; 62 + } 63 + 64 + host_stream = snd_hdac_ext_cstream_assign(bus, cstream); 65 + if (!host_stream) { 66 + dev_err(dai->dev, "Failed to assign HDAudio stream for extraction\n"); 67 + return -EBUSY; 68 + } 69 + 70 + adev->extractor = host_stream; 71 + hdac_stream(host_stream)->curr_pos = 0; 72 + cstream->runtime->private_data = host_stream; 73 + 74 + return 0; 75 + } 76 + 77 + static int avs_probe_compr_free(struct snd_compr_stream *cstream, struct snd_soc_dai *dai) 78 + { 79 + struct hdac_ext_stream *host_stream = avs_compr_get_host_stream(cstream); 80 + struct avs_dev *adev = to_avs_dev(dai->dev); 81 + struct avs_probe_point_desc *desc; 82 + /* Extractor node identifier. */ 83 + unsigned int vindex = INVALID_NODE_ID.vindex; 84 + size_t num_desc; 85 + int i, ret; 86 + 87 + /* Disconnect all probe points. */ 88 + ret = avs_ipc_probe_get_points(adev, &desc, &num_desc); 89 + if (ret) { 90 + dev_err(dai->dev, "get probe points failed: %d\n", ret); 91 + ret = AVS_IPC_RET(ret); 92 + goto exit; 93 + } 94 + 95 + for (i = 0; i < num_desc; i++) 96 + if (desc[i].node_id.vindex == vindex) 97 + avs_ipc_probe_disconnect_points(adev, &desc[i].id, 1); 98 + kfree(desc); 99 + 100 + exit: 101 + if (adev->num_probe_streams) { 102 + adev->num_probe_streams--; 103 + if (!adev->num_probe_streams) { 104 + avs_dsp_delete_probe(adev); 105 + avs_dsp_enable_d0ix(adev); 106 + } 107 + } 108 + 109 + snd_hdac_stream_cleanup(hdac_stream(host_stream)); 110 + hdac_stream(host_stream)->prepared = 0; 111 + snd_hdac_ext_stream_release(host_stream, HDAC_EXT_STREAM_TYPE_HOST); 112 + 113 + snd_compr_free_pages(cstream); 114 + adev->extractor = NULL; 115 + 116 + return ret; 117 + } 118 + 119 + static int avs_probe_compr_set_params(struct snd_compr_stream *cstream, 120 + struct snd_compr_params *params, struct snd_soc_dai *dai) 121 + { 122 + struct hdac_ext_stream *host_stream = avs_compr_get_host_stream(cstream); 123 + struct snd_compr_runtime *rtd = cstream->runtime; 124 + struct avs_dev *adev = to_avs_dev(dai->dev); 125 + /* compr params do not store bit depth, default to S32_LE. */ 126 + snd_pcm_format_t format = SNDRV_PCM_FORMAT_S32_LE; 127 + unsigned int format_val; 128 + int bps, ret; 129 + 130 + hdac_stream(host_stream)->bufsize = 0; 131 + hdac_stream(host_stream)->period_bytes = 0; 132 + hdac_stream(host_stream)->format_val = 0; 133 + cstream->dma_buffer.dev.type = SNDRV_DMA_TYPE_DEV_SG; 134 + cstream->dma_buffer.dev.dev = adev->dev; 135 + 136 + ret = snd_compr_malloc_pages(cstream, rtd->buffer_size); 137 + if (ret < 0) 138 + return ret; 139 + bps = snd_pcm_format_physical_width(format); 140 + if (bps < 0) 141 + return bps; 142 + format_val = snd_hdac_calc_stream_format(params->codec.sample_rate, params->codec.ch_out, 143 + format, bps, 0); 144 + ret = snd_hdac_stream_set_params(hdac_stream(host_stream), format_val); 145 + if (ret < 0) 146 + return ret; 147 + ret = snd_hdac_stream_setup(hdac_stream(host_stream)); 148 + if (ret < 0) 149 + return ret; 150 + 151 + hdac_stream(host_stream)->prepared = 1; 152 + 153 + if (!adev->num_probe_streams) { 154 + union avs_connector_node_id node_id; 155 + 156 + /* D0ix not allowed during probing. */ 157 + ret = avs_dsp_disable_d0ix(adev); 158 + if (ret) 159 + return ret; 160 + 161 + node_id.vindex = hdac_stream(host_stream)->stream_tag - 1; 162 + node_id.dma_type = AVS_DMA_HDA_HOST_INPUT; 163 + 164 + ret = avs_dsp_init_probe(adev, node_id, rtd->dma_bytes); 165 + if (ret < 0) { 166 + dev_err(dai->dev, "probe init failed: %d\n", ret); 167 + avs_dsp_enable_d0ix(adev); 168 + return ret; 169 + } 170 + } 171 + 172 + adev->num_probe_streams++; 173 + return 0; 174 + } 175 + 176 + static int avs_probe_compr_trigger(struct snd_compr_stream *cstream, int cmd, 177 + struct snd_soc_dai *dai) 178 + { 179 + struct hdac_ext_stream *host_stream = avs_compr_get_host_stream(cstream); 180 + struct avs_dev *adev = to_avs_dev(dai->dev); 181 + struct hdac_bus *bus = &adev->base.core; 182 + unsigned long cookie; 183 + 184 + if (!hdac_stream(host_stream)->prepared) 185 + return -EPIPE; 186 + 187 + switch (cmd) { 188 + case SNDRV_PCM_TRIGGER_START: 189 + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 190 + case SNDRV_PCM_TRIGGER_RESUME: 191 + spin_lock_irqsave(&bus->reg_lock, cookie); 192 + snd_hdac_stream_start(hdac_stream(host_stream), true); 193 + spin_unlock_irqrestore(&bus->reg_lock, cookie); 194 + break; 195 + 196 + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 197 + case SNDRV_PCM_TRIGGER_SUSPEND: 198 + case SNDRV_PCM_TRIGGER_STOP: 199 + spin_lock_irqsave(&bus->reg_lock, cookie); 200 + snd_hdac_stream_stop(hdac_stream(host_stream)); 201 + spin_unlock_irqrestore(&bus->reg_lock, cookie); 202 + break; 203 + 204 + default: 205 + return -EINVAL; 206 + } 207 + 208 + return 0; 209 + } 210 + 211 + static int avs_probe_compr_pointer(struct snd_compr_stream *cstream, 212 + struct snd_compr_tstamp *tstamp, struct snd_soc_dai *dai) 213 + { 214 + struct hdac_ext_stream *host_stream = avs_compr_get_host_stream(cstream); 215 + struct snd_soc_pcm_stream *pstream; 216 + 217 + pstream = &dai->driver->capture; 218 + tstamp->copied_total = hdac_stream(host_stream)->curr_pos; 219 + tstamp->sampling_rate = snd_pcm_rate_bit_to_rate(pstream->rates); 220 + 221 + return 0; 222 + } 223 + 224 + static int avs_probe_compr_copy(struct snd_soc_component *comp, struct snd_compr_stream *cstream, 225 + char __user *buf, size_t count) 226 + { 227 + struct snd_compr_runtime *rtd = cstream->runtime; 228 + unsigned int offset, n; 229 + void *ptr; 230 + int ret; 231 + 232 + if (count > rtd->buffer_size) 233 + count = rtd->buffer_size; 234 + 235 + div_u64_rem(rtd->total_bytes_transferred, rtd->buffer_size, &offset); 236 + ptr = rtd->dma_area + offset; 237 + n = rtd->buffer_size - offset; 238 + 239 + if (count < n) { 240 + ret = copy_to_user(buf, ptr, count); 241 + } else { 242 + ret = copy_to_user(buf, ptr, n); 243 + ret += copy_to_user(buf + n, rtd->dma_area, count - n); 244 + } 245 + 246 + if (ret) 247 + return count - ret; 248 + return count; 249 + } 250 + 251 + __maybe_unused 252 + static const struct snd_soc_cdai_ops avs_probe_dai_ops = { 253 + .startup = avs_probe_compr_open, 254 + .shutdown = avs_probe_compr_free, 255 + .set_params = avs_probe_compr_set_params, 256 + .trigger = avs_probe_compr_trigger, 257 + .pointer = avs_probe_compr_pointer, 258 + }; 259 + 260 + __maybe_unused 261 + static const struct snd_compress_ops avs_probe_compress_ops = { 262 + .copy = avs_probe_compr_copy, 263 + };