1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 2 // 3 // This file is provided under a dual BSD/GPLv2 license. When using or 4 // redistributing this file, you may do so under either license. 5 // 6 // Copyright(c) 2023 Intel Corporation 7 // 8 9 #include <linux/firmware.h> 10 #include <sound/sof.h> 11 #include <sound/sof/ext_manifest4.h> 12 #include "sof-priv.h" 13 14 static int sof_test_firmware_file(struct device *dev, 15 struct sof_loadable_file_profile *profile, 16 enum sof_ipc_type *ipc_type_to_adjust) 17 { 18 enum sof_ipc_type fw_ipc_type; 19 const struct firmware *fw; 20 const char *fw_filename; 21 const u32 *magic; 22 int ret; 23 24 fw_filename = kasprintf(GFP_KERNEL, "%s/%s", profile->fw_path, 25 profile->fw_name); 26 if (!fw_filename) 27 return -ENOMEM; 28 29 ret = firmware_request_nowarn(&fw, fw_filename, dev); 30 if (ret < 0) { 31 dev_dbg(dev, "Failed to open firmware file: %s\n", fw_filename); 32 kfree(fw_filename); 33 return ret; 34 } 35 36 /* firmware file exists, check the magic number */ 37 magic = (const u32 *)fw->data; 38 switch (*magic) { 39 case SOF_EXT_MAN_MAGIC_NUMBER: 40 fw_ipc_type = SOF_IPC_TYPE_3; 41 break; 42 case SOF_EXT_MAN4_MAGIC_NUMBER: 43 fw_ipc_type = SOF_IPC_TYPE_4; 44 break; 45 default: 46 dev_err(dev, "Invalid firmware magic: %#x\n", *magic); 47 ret = -EINVAL; 48 goto out; 49 } 50 51 if (ipc_type_to_adjust) { 52 *ipc_type_to_adjust = fw_ipc_type; 53 } else if (fw_ipc_type != profile->ipc_type) { 54 dev_err(dev, 55 "ipc type mismatch between %s and expected: %d vs %d\n", 56 fw_filename, fw_ipc_type, profile->ipc_type); 57 ret = -EINVAL; 58 } 59 out: 60 release_firmware(fw); 61 kfree(fw_filename); 62 63 return ret; 64 } 65 66 static int sof_test_topology_file(struct device *dev, 67 struct sof_loadable_file_profile *profile) 68 { 69 const struct firmware *fw; 70 const char *tplg_filename; 71 int ret; 72 73 if (!profile->tplg_path || !profile->tplg_name) 74 return 0; 75 76 /* Dummy topology does not exist and should not be used */ 77 if (strstr(profile->tplg_name, "dummy")) 78 return 0; 79 80 tplg_filename = kasprintf(GFP_KERNEL, "%s/%s", profile->tplg_path, 81 profile->tplg_name); 82 if (!tplg_filename) 83 return -ENOMEM; 84 85 ret = firmware_request_nowarn(&fw, tplg_filename, dev); 86 if (!ret) 87 release_firmware(fw); 88 else 89 dev_dbg(dev, "Failed to open topology file: %s\n", tplg_filename); 90 91 kfree(tplg_filename); 92 93 return ret; 94 } 95 96 static bool sof_platform_uses_generic_loader(struct snd_sof_dev *sdev) 97 { 98 return (sdev->pdata->desc->ops->load_firmware == snd_sof_load_firmware_raw || 99 sdev->pdata->desc->ops->load_firmware == snd_sof_load_firmware_memcpy); 100 } 101 102 static int 103 sof_file_profile_for_ipc_type(struct snd_sof_dev *sdev, 104 enum sof_ipc_type ipc_type, 105 const struct sof_dev_desc *desc, 106 struct sof_loadable_file_profile *base_profile, 107 struct sof_loadable_file_profile *out_profile) 108 { 109 struct snd_sof_pdata *plat_data = sdev->pdata; 110 bool fw_lib_path_allocated = false; 111 struct device *dev = sdev->dev; 112 bool fw_path_allocated = false; 113 int ret = 0; 114 115 /* firmware path */ 116 if (base_profile->fw_path) { 117 out_profile->fw_path = base_profile->fw_path; 118 } else if (base_profile->fw_path_postfix) { 119 out_profile->fw_path = devm_kasprintf(dev, GFP_KERNEL, "%s/%s", 120 desc->default_fw_path[ipc_type], 121 base_profile->fw_path_postfix); 122 if (!out_profile->fw_path) 123 return -ENOMEM; 124 125 fw_path_allocated = true; 126 } else { 127 out_profile->fw_path = desc->default_fw_path[ipc_type]; 128 } 129 130 /* firmware filename */ 131 if (base_profile->fw_name) 132 out_profile->fw_name = base_profile->fw_name; 133 else 134 out_profile->fw_name = desc->default_fw_filename[ipc_type]; 135 136 /* 137 * Check the custom firmware path/filename and adjust the ipc_type to 138 * match with the existing file for the remaining path configuration. 139 * 140 * For default path and firmware name do a verification before 141 * continuing further. 142 */ 143 if ((base_profile->fw_path || base_profile->fw_name) && 144 sof_platform_uses_generic_loader(sdev)) { 145 ret = sof_test_firmware_file(dev, out_profile, &ipc_type); 146 if (ret) 147 return ret; 148 149 if (!(desc->ipc_supported_mask & BIT(ipc_type))) { 150 dev_err(dev, "Unsupported IPC type %d needed by %s/%s\n", 151 ipc_type, out_profile->fw_path, 152 out_profile->fw_name); 153 return -EINVAL; 154 } 155 } 156 157 /* firmware library path */ 158 if (base_profile->fw_lib_path) { 159 out_profile->fw_lib_path = base_profile->fw_lib_path; 160 } else if (desc->default_lib_path[ipc_type]) { 161 if (base_profile->fw_lib_path_postfix) { 162 out_profile->fw_lib_path = devm_kasprintf(dev, 163 GFP_KERNEL, "%s/%s", 164 desc->default_lib_path[ipc_type], 165 base_profile->fw_lib_path_postfix); 166 if (!out_profile->fw_lib_path) { 167 ret = -ENOMEM; 168 goto out; 169 } 170 171 fw_lib_path_allocated = true; 172 } else { 173 out_profile->fw_lib_path = desc->default_lib_path[ipc_type]; 174 } 175 } 176 177 if (base_profile->fw_path_postfix) 178 out_profile->fw_path_postfix = base_profile->fw_path_postfix; 179 180 if (base_profile->fw_lib_path_postfix) 181 out_profile->fw_lib_path_postfix = base_profile->fw_lib_path_postfix; 182 183 /* topology path */ 184 if (base_profile->tplg_path) 185 out_profile->tplg_path = base_profile->tplg_path; 186 else 187 out_profile->tplg_path = desc->default_tplg_path[ipc_type]; 188 189 /* topology name */ 190 out_profile->tplg_name = plat_data->tplg_filename; 191 192 out_profile->ipc_type = ipc_type; 193 194 /* Test only default firmware file */ 195 if ((!base_profile->fw_path && !base_profile->fw_name) && 196 sof_platform_uses_generic_loader(sdev)) 197 ret = sof_test_firmware_file(dev, out_profile, NULL); 198 199 if (!ret) 200 ret = sof_test_topology_file(dev, out_profile); 201 202 out: 203 if (ret) { 204 /* Free up path strings created with devm_kasprintf */ 205 if (fw_path_allocated) 206 devm_kfree(dev, out_profile->fw_path); 207 if (fw_lib_path_allocated) 208 devm_kfree(dev, out_profile->fw_lib_path); 209 210 memset(out_profile, 0, sizeof(*out_profile)); 211 } 212 213 return ret; 214 } 215 216 static void 217 sof_print_missing_firmware_info(struct snd_sof_dev *sdev, 218 enum sof_ipc_type ipc_type, 219 struct sof_loadable_file_profile *base_profile) 220 { 221 struct snd_sof_pdata *plat_data = sdev->pdata; 222 const struct sof_dev_desc *desc = plat_data->desc; 223 struct device *dev = sdev->dev; 224 int ipc_type_count, i; 225 char *marker; 226 227 dev_err(dev, "SOF firmware and/or topology file not found.\n"); 228 dev_info(dev, "Supported default profiles\n"); 229 230 if (IS_ENABLED(CONFIG_SND_SOC_SOF_ALLOW_FALLBACK_TO_NEWER_IPC_VERSION)) 231 ipc_type_count = SOF_IPC_TYPE_COUNT - 1; 232 else 233 ipc_type_count = base_profile->ipc_type; 234 235 for (i = 0; i <= ipc_type_count; i++) { 236 if (!(desc->ipc_supported_mask & BIT(i))) 237 continue; 238 239 if (i == ipc_type) 240 marker = "Requested"; 241 else 242 marker = "Fallback"; 243 244 dev_info(dev, "- ipc type %d (%s):\n", i, marker); 245 if (base_profile->fw_path_postfix) 246 dev_info(dev, " Firmware file: %s/%s/%s\n", 247 desc->default_fw_path[i], 248 base_profile->fw_path_postfix, 249 desc->default_fw_filename[i]); 250 else 251 dev_info(dev, " Firmware file: %s/%s\n", 252 desc->default_fw_path[i], 253 desc->default_fw_filename[i]); 254 255 dev_info(dev, " Topology file: %s/%s\n", 256 desc->default_tplg_path[i], 257 plat_data->tplg_filename); 258 } 259 260 if (base_profile->fw_path || base_profile->fw_name || 261 base_profile->tplg_path || base_profile->tplg_name) 262 dev_info(dev, "Verify the path/name override module parameters.\n"); 263 264 dev_info(dev, "Check if you have 'sof-firmware' package installed.\n"); 265 dev_info(dev, "Optionally it can be manually downloaded from:\n"); 266 dev_info(dev, " https://github.com/thesofproject/sof-bin/\n"); 267 } 268 269 static void sof_print_profile_info(struct snd_sof_dev *sdev, 270 enum sof_ipc_type ipc_type, 271 struct sof_loadable_file_profile *profile) 272 { 273 struct snd_sof_pdata *plat_data = sdev->pdata; 274 struct device *dev = sdev->dev; 275 276 if (ipc_type != profile->ipc_type) 277 dev_info(dev, 278 "Using fallback IPC type %d (requested type was %d)\n", 279 profile->ipc_type, ipc_type); 280 281 dev_info(dev, "Firmware paths/files for ipc type %d:\n", profile->ipc_type); 282 283 /* The firmware path is only valid when generic loader is used */ 284 if (sof_platform_uses_generic_loader(sdev)) 285 dev_info(dev, " Firmware file: %s/%s\n", 286 profile->fw_path, profile->fw_name); 287 288 if (profile->fw_lib_path) 289 dev_info(dev, " Firmware lib path: %s\n", profile->fw_lib_path); 290 291 if (plat_data->machine && plat_data->machine->get_function_tplg_files && 292 !plat_data->disable_function_topology) 293 dev_info(dev, " Topology file: function topologies\n"); 294 else 295 dev_info(dev, " Topology file: %s/%s\n", 296 profile->tplg_path, profile->tplg_name); 297 } 298 299 int sof_create_ipc_file_profile(struct snd_sof_dev *sdev, 300 struct sof_loadable_file_profile *base_profile, 301 struct sof_loadable_file_profile *out_profile) 302 { 303 const struct sof_dev_desc *desc = sdev->pdata->desc; 304 int ipc_fallback_start, ret, i; 305 306 memset(out_profile, 0, sizeof(*out_profile)); 307 308 ret = sof_file_profile_for_ipc_type(sdev, base_profile->ipc_type, desc, 309 base_profile, out_profile); 310 if (!ret) 311 goto out; 312 313 /* 314 * No firmware file was found for the requested IPC type, as fallback 315 * if SND_SOC_SOF_ALLOW_FALLBACK_TO_NEWER_IPC_VERSION is selected, check 316 * all IPC versions in a backwards direction (from newer to older) 317 * if SND_SOC_SOF_ALLOW_FALLBACK_TO_NEWER_IPC_VERSION is not selected, 318 * check only older IPC versions than the selected/default version 319 */ 320 if (IS_ENABLED(CONFIG_SND_SOC_SOF_ALLOW_FALLBACK_TO_NEWER_IPC_VERSION)) 321 ipc_fallback_start = SOF_IPC_TYPE_COUNT - 1; 322 else 323 ipc_fallback_start = (int)base_profile->ipc_type - 1; 324 325 for (i = ipc_fallback_start; i >= 0 ; i--) { 326 if (i == base_profile->ipc_type || 327 !(desc->ipc_supported_mask & BIT(i))) 328 continue; 329 330 ret = sof_file_profile_for_ipc_type(sdev, i, desc, base_profile, 331 out_profile); 332 if (!ret) 333 break; 334 } 335 336 out: 337 if (ret) 338 sof_print_missing_firmware_info(sdev, base_profile->ipc_type, 339 base_profile); 340 else 341 sof_print_profile_info(sdev, base_profile->ipc_type, out_profile); 342 343 return ret; 344 } 345 EXPORT_SYMBOL(sof_create_ipc_file_profile); 346