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

ASoC: SOF: sof-client-probes-ipc4: Query available

Merge series from Peter Ujfalusi <peter.ujfalusi@linux.intel.com>:

This series improves the IPC4 probes implementation by improving the
report quality and adds support for querying the available probes
on the firmware side.

+220 -25
+4
include/sound/sof/ipc4/header.h
··· 326 326 #define SOF_IPC4_MOD_INSTANCE_SHIFT 16 327 327 #define SOF_IPC4_MOD_INSTANCE_MASK GENMASK(23, 16) 328 328 #define SOF_IPC4_MOD_INSTANCE(x) ((x) << SOF_IPC4_MOD_INSTANCE_SHIFT) 329 + #define SOF_IPC4_MOD_INSTANCE_GET(x) (((x) & SOF_IPC4_MOD_INSTANCE_MASK) \ 330 + >> SOF_IPC4_MOD_INSTANCE_SHIFT) 329 331 330 332 #define SOF_IPC4_MOD_ID_SHIFT 0 331 333 #define SOF_IPC4_MOD_ID_MASK GENMASK(15, 0) 332 334 #define SOF_IPC4_MOD_ID(x) ((x) << SOF_IPC4_MOD_ID_SHIFT) 335 + #define SOF_IPC4_MOD_ID_GET(x) (((x) & SOF_IPC4_MOD_ID_MASK) \ 336 + >> SOF_IPC4_MOD_ID_SHIFT) 333 337 334 338 /* init module ipc msg */ 335 339 #define SOF_IPC4_MOD_EXT_PARAM_SIZE_SHIFT 0
+18 -7
sound/soc/sof/sof-client-probes-ipc3.c
··· 100 100 } 101 101 102 102 static int ipc3_probes_info(struct sof_client_dev *cdev, unsigned int cmd, 103 - void **params, size_t *num_params) 103 + void **params, size_t *num_params, 104 + enum sof_probe_info_type type) 104 105 { 105 106 size_t max_msg_size = sof_client_get_ipc_max_payload_size(cdev); 107 + struct device *dev = &cdev->auxdev.dev; 106 108 struct sof_ipc_probe_info_params msg = {{{0}}}; 107 109 struct sof_ipc_probe_info_params *reply; 108 110 size_t bytes; ··· 112 110 113 111 *params = NULL; 114 112 *num_params = 0; 113 + 114 + if (type != PROBES_INFO_ACTIVE_PROBES) { 115 + dev_err(dev, "%s: info type %u not supported", __func__, type); 116 + return -EOPNOTSUPP; 117 + } 115 118 116 119 reply = kzalloc(max_msg_size, GFP_KERNEL); 117 120 if (!reply) ··· 149 142 } 150 143 151 144 /** 152 - * ipc3_probes_points_info - retrieve list of active probe points 145 + * ipc3_probes_points_info - retrieve list of probe points 153 146 * @cdev: SOF client device 154 147 * @desc: Returned list of active probes 155 148 * @num_desc: Returned count of active probes 149 + * @type: Either PROBES_INFO_ACTIVE_PROBES or PROBES_INFO_AVAILABE_PROBES 156 150 * 157 - * Host sends PROBE_POINT_INFO request to obtain list of active probe 158 - * points, valid for disconnection when given probe is no longer 159 - * required. 151 + * If type is PROBES_INFO_ACTIVE_PROBES, host sends PROBE_POINT_INFO 152 + * request to obtain list of active probe points, valid for 153 + * disconnection when given probe is no longer required. 154 + * 155 + * Type PROBES_INFO_AVAILABE_PROBES is not yet supported. 160 156 */ 161 157 static int ipc3_probes_points_info(struct sof_client_dev *cdev, 162 158 struct sof_probe_point_desc **desc, 163 - size_t *num_desc) 159 + size_t *num_desc, 160 + enum sof_probe_info_type type) 164 161 { 165 162 return ipc3_probes_info(cdev, SOF_IPC_PROBE_POINT_INFO, 166 - (void **)desc, num_desc); 163 + (void **)desc, num_desc, type); 167 164 } 168 165 169 166 /**
+126 -8
sound/soc/sof/sof-client-probes-ipc4.c
··· 8 8 #include <sound/soc.h> 9 9 #include <sound/sof/ipc4/header.h> 10 10 #include <uapi/sound/sof/header.h> 11 - #include "sof-priv.h" 11 + #include "sof-audio.h" 12 12 #include "ipc4-priv.h" 13 13 #include "sof-client.h" 14 14 #include "sof-client-probes.h" ··· 28 28 SOF_IPC4_PROBE_INJECTION_DMA_DETACH, 29 29 SOF_IPC4_PROBE_POINTS, 30 30 SOF_IPC4_PROBE_POINTS_DISCONNECT, 31 + SOF_IPC4_PROBE_POINTS_AVAILABLE, 31 32 }; 32 33 33 34 struct sof_ipc4_probe_gtw_cfg { ··· 50 49 SOF_IPC4_PROBE_TYPE_INTERNAL 51 50 }; 52 51 52 + #define SOF_IPC4_PROBE_TYPE_SHIFT 24 53 + #define SOF_IPC4_PROBE_TYPE_MASK GENMASK(25, 24) 54 + #define SOF_IPC4_PROBE_TYPE_GET(x) (((x) & SOF_IPC4_PROBE_TYPE_MASK) \ 55 + >> SOF_IPC4_PROBE_TYPE_SHIFT) 56 + #define SOF_IPC4_PROBE_IDX_SHIFT 26 57 + #define SOF_IPC4_PROBE_IDX_MASK GENMASK(31, 26) 58 + #define SOF_IPC4_PROBE_IDX_GET(x) (((x) & SOF_IPC4_PROBE_IDX_MASK) \ 59 + >> SOF_IPC4_PROBE_IDX_SHIFT) 60 + 53 61 struct sof_ipc4_probe_point { 54 62 u32 point_id; 55 63 u32 purpose; 56 64 u32 stream_tag; 57 65 } __packed __aligned(4); 58 66 67 + struct sof_ipc4_probe_info { 68 + unsigned int num_elems; 69 + DECLARE_FLEX_ARRAY(struct sof_ipc4_probe_point, points); 70 + } __packed; 71 + 59 72 #define INVALID_PIPELINE_ID 0xFF 73 + 74 + static const char *sof_probe_ipc4_type_string(u32 type) 75 + { 76 + switch (type) { 77 + case SOF_IPC4_PROBE_TYPE_INPUT: 78 + return "input"; 79 + case SOF_IPC4_PROBE_TYPE_OUTPUT: 80 + return "output"; 81 + case SOF_IPC4_PROBE_TYPE_INTERNAL: 82 + return "internal"; 83 + default: 84 + return "UNKNOWN"; 85 + } 86 + } 60 87 61 88 /** 62 89 * sof_ipc4_probe_get_module_info - Get IPC4 module info for probe module ··· 193 164 } 194 165 195 166 /** 196 - * ipc4_probes_points_info - retrieve list of active probe points 167 + * ipc4_probes_points_info - retrieve list of probe points 197 168 * @cdev: SOF client device 198 169 * @desc: Returned list of active probes 199 170 * @num_desc: Returned count of active probes 171 + * @type: Either PROBES_INFO_ACTIVE_PROBES or PROBES_INFO_AVAILABE_PROBES 200 172 * @return: 0 on success, negative error code on error 201 173 * 202 - * Dummy implementation returning empty list of probes. 174 + * Returns list if active probe points if type is 175 + * PROBES_INFO_ACTIVE_PROBES, or list of all available probe points if 176 + * type is PROBES_INFO_AVAILABE_PROBES. 203 177 */ 204 178 static int ipc4_probes_points_info(struct sof_client_dev *cdev, 205 179 struct sof_probe_point_desc **desc, 206 - size_t *num_desc) 180 + size_t *num_desc, 181 + enum sof_probe_info_type type) 207 182 { 208 - /* TODO: Firmware side implementation needed first */ 209 - *desc = NULL; 210 - *num_desc = 0; 183 + struct sof_man4_module *mentry = sof_ipc4_probe_get_module_info(cdev); 184 + struct device *dev = &cdev->auxdev.dev; 185 + struct sof_ipc4_probe_info *info; 186 + struct sof_ipc4_msg msg; 187 + u32 param_id; 188 + int i, ret; 189 + 190 + if (!mentry) 191 + return -ENODEV; 192 + 193 + switch (type) { 194 + case PROBES_INFO_ACTIVE_PROBES: 195 + param_id = SOF_IPC4_PROBE_POINTS; 196 + break; 197 + case PROBES_INFO_AVAILABE_PROBES: 198 + param_id = SOF_IPC4_PROBE_POINTS_AVAILABLE; 199 + break; 200 + default: 201 + dev_err(dev, "%s: info type %u not supported", __func__, type); 202 + return -EOPNOTSUPP; 203 + } 204 + 205 + msg.primary = mentry->id; 206 + msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 207 + msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); 208 + 209 + msg.extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(param_id); 210 + 211 + msg.data_size = sof_client_get_ipc_max_payload_size(cdev); 212 + msg.data_ptr = kzalloc(msg.data_size, GFP_KERNEL); 213 + if (!msg.data_ptr) 214 + return -ENOMEM; 215 + 216 + ret = sof_client_ipc_set_get_data(cdev, &msg, false); 217 + if (ret) { 218 + kfree(msg.data_ptr); 219 + return ret; 220 + } 221 + info = msg.data_ptr; 222 + *num_desc = info->num_elems; 223 + dev_dbg(dev, "%s: got %zu probe points", __func__, *num_desc); 224 + 225 + *desc = kzalloc(*num_desc * sizeof(**desc), GFP_KERNEL); 226 + if (!*desc) { 227 + kfree(msg.data_ptr); 228 + return -ENOMEM; 229 + } 230 + 231 + for (i = 0; i < *num_desc; i++) { 232 + (*desc)[i].buffer_id = info->points[i].point_id; 233 + (*desc)[i].purpose = info->points[i].purpose; 234 + (*desc)[i].stream_tag = info->points[i].stream_tag; 235 + } 236 + kfree(msg.data_ptr); 237 + 211 238 return 0; 239 + } 240 + 241 + /** 242 + * ipc4_probes_point_print - Human readable print of probe point descriptor 243 + * @cdev: SOF client device 244 + * @buf: Buffer to print to 245 + * @size: Available bytes in buffer 246 + * @desc: Describes the probe point to print 247 + * @return: Number of bytes printed or an error code (snprintf return value) 248 + */ 249 + static int ipc4_probes_point_print(struct sof_client_dev *cdev, char *buf, size_t size, 250 + struct sof_probe_point_desc *desc) 251 + { 252 + struct device *dev = &cdev->auxdev.dev; 253 + struct snd_sof_widget *swidget; 254 + int ret; 255 + 256 + swidget = sof_client_ipc4_find_swidget_by_id(cdev, SOF_IPC4_MOD_ID_GET(desc->buffer_id), 257 + SOF_IPC4_MOD_INSTANCE_GET(desc->buffer_id)); 258 + if (!swidget) 259 + dev_err(dev, "%s: Failed to find widget for module %lu.%lu\n", 260 + __func__, SOF_IPC4_MOD_ID_GET(desc->buffer_id), 261 + SOF_IPC4_MOD_INSTANCE_GET(desc->buffer_id)); 262 + 263 + ret = snprintf(buf, size, "%#x,%#x,%#x\t%s %s buf idx %lu %s\n", 264 + desc->buffer_id, desc->purpose, desc->stream_tag, 265 + swidget ? swidget->widget->name : "<unknown>", 266 + sof_probe_ipc4_type_string(SOF_IPC4_PROBE_TYPE_GET(desc->buffer_id)), 267 + SOF_IPC4_PROBE_IDX_GET(desc->buffer_id), 268 + desc->stream_tag ? "(connected)" : ""); 269 + 270 + return ret; 212 271 } 213 272 214 273 /** ··· 319 202 int i, ret; 320 203 321 204 if (!mentry) 322 - return -ENODEV; 205 + return -EOPNOTSUPP; 323 206 324 207 /* The sof_probe_point_desc and sof_ipc4_probe_point structs 325 208 * are of same size and even the integers are the same in the ··· 403 286 .init = ipc4_probes_init, 404 287 .deinit = ipc4_probes_deinit, 405 288 .points_info = ipc4_probes_points_info, 289 + .point_print = ipc4_probes_point_print, 406 290 .points_add = ipc4_probes_points_add, 407 291 .points_remove = ipc4_probes_points_remove, 408 292 };
+49 -9
sound/soc/sof/sof-client-probes.c
··· 17 17 18 18 #include <sound/soc.h> 19 19 #include <sound/sof/header.h> 20 + #include <sound/sof/ipc4/header.h> 20 21 #include "sof-client.h" 21 22 #include "sof-client-probes.h" 23 + #include "sof-audio.h" 24 + 25 + #ifdef CONFIG_SND_SOC_SOF_IPC4 26 + #include "ipc4-priv.h" 27 + #endif 22 28 23 29 #define SOF_PROBES_SUSPEND_DELAY_MS 3000 24 30 /* only extraction supported for now */ ··· 75 69 int i, ret; 76 70 77 71 /* disconnect all probe points */ 78 - ret = ipc->points_info(cdev, &desc, &num_desc); 72 + ret = ipc->points_info(cdev, &desc, &num_desc, 73 + PROBES_INFO_ACTIVE_PROBES); 79 74 if (ret < 0) { 80 75 dev_err(dai->dev, "Failed to get probe points: %d\n", ret); 81 76 goto exit; ··· 196 189 }; 197 190 198 191 static ssize_t sof_probes_dfs_points_read(struct file *file, char __user *to, 199 - size_t count, loff_t *ppos) 192 + size_t count, loff_t *ppos, 193 + enum sof_probe_info_type type) 200 194 { 201 195 struct sof_client_dev *cdev = file->private_data; 202 196 struct sof_probes_priv *priv = cdev->data; ··· 224 216 goto exit; 225 217 } 226 218 227 - ret = ipc->points_info(cdev, &desc, &num_desc); 219 + ret = ipc->points_info(cdev, &desc, &num_desc, type); 228 220 if (ret < 0) 229 221 goto pm_error; 230 222 231 223 for (i = 0; i < num_desc; i++) { 232 224 offset = strlen(buf); 233 225 remaining = PAGE_SIZE - offset; 234 - ret = snprintf(buf + offset, remaining, 235 - "Id: %#010x Purpose: %u Node id: %#x\n", 236 - desc[i].buffer_id, desc[i].purpose, desc[i].stream_tag); 226 + if (ipc->point_print) 227 + ret = ipc->point_print(cdev, buf + offset, remaining, &desc[i]); 228 + else 229 + ret = snprintf(buf + offset, remaining, 230 + "Id: %#010x Purpose: %u Node id: %#x\n", 231 + desc[i].buffer_id, desc[i].purpose, desc[i].stream_tag); 232 + 237 233 if (ret < 0 || ret >= remaining) { 238 234 /* truncate the output buffer at the last full line */ 239 235 buf[offset] = '\0'; ··· 257 245 exit: 258 246 kfree(buf); 259 247 return ret; 248 + } 249 + 250 + static ssize_t sof_probes_dfs_active_points_read(struct file *file, 251 + char __user *to, 252 + size_t count, loff_t *ppos) 253 + { 254 + return sof_probes_dfs_points_read(file, to, count, ppos, 255 + PROBES_INFO_ACTIVE_PROBES); 256 + } 257 + 258 + static ssize_t sof_probes_dfs_available_points_read(struct file *file, 259 + char __user *to, 260 + size_t count, loff_t *ppos) 261 + { 262 + return sof_probes_dfs_points_read(file, to, count, ppos, 263 + PROBES_INFO_AVAILABE_PROBES); 260 264 } 261 265 262 266 static ssize_t ··· 324 296 return ret; 325 297 } 326 298 327 - static const struct file_operations sof_probes_points_fops = { 299 + static const struct file_operations sof_probes_active_points_fops = { 328 300 .open = simple_open, 329 - .read = sof_probes_dfs_points_read, 301 + .read = sof_probes_dfs_active_points_read, 330 302 .write = sof_probes_dfs_points_write, 303 + .llseek = default_llseek, 304 + 305 + .owner = THIS_MODULE, 306 + }; 307 + 308 + static const struct file_operations sof_probes_available_points_fops = { 309 + .open = simple_open, 310 + .read = sof_probes_dfs_available_points_read, 331 311 .llseek = default_llseek, 332 312 333 313 .owner = THIS_MODULE, ··· 485 449 486 450 /* create read-write probes_points debugfs entry */ 487 451 priv->dfs_points = debugfs_create_file("probe_points", 0644, dfsroot, 488 - cdev, &sof_probes_points_fops); 452 + cdev, &sof_probes_active_points_fops); 489 453 490 454 /* create read-write probe_points_remove debugfs entry */ 491 455 priv->dfs_points_remove = debugfs_create_file("probe_points_remove", 0644, 492 456 dfsroot, cdev, 493 457 &sof_probes_points_remove_fops); 458 + 459 + /* create read-write probes_points debugfs entry */ 460 + priv->dfs_points = debugfs_create_file("probe_points_available", 0644, dfsroot, 461 + cdev, &sof_probes_available_points_fops); 494 462 495 463 links = devm_kcalloc(dev, SOF_PROBES_NUM_DAI_LINKS, sizeof(*links), GFP_KERNEL); 496 464 cpus = devm_kcalloc(dev, SOF_PROBES_NUM_DAI_LINKS, sizeof(*cpus), GFP_KERNEL);
+8 -1
sound/soc/sof/sof-client-probes.h
··· 34 34 unsigned int stream_tag; 35 35 } __packed; 36 36 37 + enum sof_probe_info_type { 38 + PROBES_INFO_ACTIVE_PROBES, 39 + PROBES_INFO_AVAILABE_PROBES, 40 + }; 41 + 37 42 struct sof_probes_ipc_ops { 38 43 int (*init)(struct sof_client_dev *cdev, u32 stream_tag, 39 44 size_t buffer_size); 40 45 int (*deinit)(struct sof_client_dev *cdev); 41 46 int (*points_info)(struct sof_client_dev *cdev, 42 47 struct sof_probe_point_desc **desc, 43 - size_t *num_desc); 48 + size_t *num_desc, enum sof_probe_info_type type); 49 + int (*point_print)(struct sof_client_dev *cdev, char *buf, size_t size, 50 + struct sof_probe_point_desc *desc); 44 51 int (*points_add)(struct sof_client_dev *cdev, 45 52 struct sof_probe_point_desc *desc, 46 53 size_t num_desc);
+13
sound/soc/sof/sof-client.c
··· 380 380 return NULL; 381 381 } 382 382 EXPORT_SYMBOL_NS_GPL(sof_client_ipc4_find_module, "SND_SOC_SOF_CLIENT"); 383 + 384 + struct snd_sof_widget *sof_client_ipc4_find_swidget_by_id(struct sof_client_dev *cdev, 385 + u32 module_id, int instance_id) 386 + { 387 + struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); 388 + 389 + if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4) 390 + return sof_ipc4_find_swidget_by_ids(sdev, module_id, instance_id); 391 + dev_err(sdev->dev, "Only supported with IPC4\n"); 392 + 393 + return NULL; 394 + } 395 + EXPORT_SYMBOL_NS_GPL(sof_client_ipc4_find_swidget_by_id, "SND_SOC_SOF_CLIENT"); 383 396 #endif 384 397 385 398 int sof_suspend_clients(struct snd_sof_dev *sdev, pm_message_t state)
+2
sound/soc/sof/sof-client.h
··· 41 41 bool set); 42 42 43 43 struct sof_ipc4_fw_module *sof_client_ipc4_find_module(struct sof_client_dev *c, const guid_t *u); 44 + struct snd_sof_widget *sof_client_ipc4_find_swidget_by_id(struct sof_client_dev *cdev, 45 + u32 module_id, int instance_id); 44 46 45 47 struct dentry *sof_client_get_debugfs_root(struct sof_client_dev *cdev); 46 48 struct device *sof_client_get_dma_dev(struct sof_client_dev *cdev);