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. All rights reserved. 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 tplg_filename = kasprintf(GFP_KERNEL, "%s/%s", profile->tplg_path, 77 profile->tplg_name); 78 if (!tplg_filename) 79 return -ENOMEM; 80 81 ret = firmware_request_nowarn(&fw, tplg_filename, dev); 82 if (!ret) 83 release_firmware(fw); 84 else 85 dev_dbg(dev, "Failed to open topology file: %s\n", tplg_filename); 86 87 kfree(tplg_filename); 88 89 return ret; 90 } 91 92 static int 93 sof_file_profile_for_ipc_type(struct snd_sof_dev *sdev, 94 enum sof_ipc_type ipc_type, 95 const struct sof_dev_desc *desc, 96 struct sof_loadable_file_profile *base_profile, 97 struct sof_loadable_file_profile *out_profile) 98 { 99 struct snd_sof_pdata *plat_data = sdev->pdata; 100 bool fw_lib_path_allocated = false; 101 struct device *dev = sdev->dev; 102 bool fw_path_allocated = false; 103 int ret = 0; 104 105 /* firmware path */ 106 if (base_profile->fw_path) { 107 out_profile->fw_path = base_profile->fw_path; 108 } else if (base_profile->fw_path_postfix) { 109 out_profile->fw_path = devm_kasprintf(dev, GFP_KERNEL, "%s/%s", 110 desc->default_fw_path[ipc_type], 111 base_profile->fw_path_postfix); 112 if (!out_profile->fw_path) 113 return -ENOMEM; 114 115 fw_path_allocated = true; 116 } else { 117 out_profile->fw_path = desc->default_fw_path[ipc_type]; 118 } 119 120 /* firmware filename */ 121 if (base_profile->fw_name) 122 out_profile->fw_name = base_profile->fw_name; 123 else 124 out_profile->fw_name = desc->default_fw_filename[ipc_type]; 125 126 /* 127 * Check the custom firmware path/filename and adjust the ipc_type to 128 * match with the existing file for the remaining path configuration. 129 * 130 * For default path and firmware name do a verification before 131 * continuing further. 132 */ 133 if (base_profile->fw_path || base_profile->fw_name) { 134 ret = sof_test_firmware_file(dev, out_profile, &ipc_type); 135 if (ret) 136 return ret; 137 138 if (!(desc->ipc_supported_mask & BIT(ipc_type))) { 139 dev_err(dev, "Unsupported IPC type %d needed by %s/%s\n", 140 ipc_type, out_profile->fw_path, 141 out_profile->fw_name); 142 return -EINVAL; 143 } 144 } 145 146 /* firmware library path */ 147 if (base_profile->fw_lib_path) { 148 out_profile->fw_lib_path = base_profile->fw_lib_path; 149 } else if (desc->default_lib_path[ipc_type]) { 150 if (base_profile->fw_lib_path_postfix) { 151 out_profile->fw_lib_path = devm_kasprintf(dev, 152 GFP_KERNEL, "%s/%s", 153 desc->default_lib_path[ipc_type], 154 base_profile->fw_lib_path_postfix); 155 if (!out_profile->fw_lib_path) { 156 ret = -ENOMEM; 157 goto out; 158 } 159 160 fw_lib_path_allocated = true; 161 } else { 162 out_profile->fw_lib_path = desc->default_lib_path[ipc_type]; 163 } 164 } 165 166 if (base_profile->fw_path_postfix) 167 out_profile->fw_path_postfix = base_profile->fw_path_postfix; 168 169 if (base_profile->fw_lib_path_postfix) 170 out_profile->fw_lib_path_postfix = base_profile->fw_lib_path_postfix; 171 172 /* topology path */ 173 if (base_profile->tplg_path) 174 out_profile->tplg_path = base_profile->tplg_path; 175 else 176 out_profile->tplg_path = desc->default_tplg_path[ipc_type]; 177 178 /* topology name */ 179 out_profile->tplg_name = plat_data->tplg_filename; 180 181 out_profile->ipc_type = ipc_type; 182 183 /* Test only default firmware file */ 184 if (!base_profile->fw_path && !base_profile->fw_name) 185 ret = sof_test_firmware_file(dev, out_profile, NULL); 186 187 if (!ret) 188 ret = sof_test_topology_file(dev, out_profile); 189 190 out: 191 if (ret) { 192 /* Free up path strings created with devm_kasprintf */ 193 if (fw_path_allocated) 194 devm_kfree(dev, out_profile->fw_path); 195 if (fw_lib_path_allocated) 196 devm_kfree(dev, out_profile->fw_lib_path); 197 198 memset(out_profile, 0, sizeof(*out_profile)); 199 } 200 201 return ret; 202 } 203 204 static void 205 sof_print_missing_firmware_info(struct snd_sof_dev *sdev, 206 enum sof_ipc_type ipc_type, 207 struct sof_loadable_file_profile *base_profile) 208 { 209 struct snd_sof_pdata *plat_data = sdev->pdata; 210 const struct sof_dev_desc *desc = plat_data->desc; 211 struct device *dev = sdev->dev; 212 int ipc_type_count, i; 213 char *marker; 214 215 dev_err(dev, "SOF firmware and/or topology file not found.\n"); 216 dev_info(dev, "Supported default profiles\n"); 217 218 if (IS_ENABLED(CONFIG_SND_SOC_SOF_ALLOW_FALLBACK_TO_NEWER_IPC_VERSION)) 219 ipc_type_count = SOF_IPC_TYPE_COUNT - 1; 220 else 221 ipc_type_count = base_profile->ipc_type; 222 223 for (i = 0; i <= ipc_type_count; i++) { 224 if (!(desc->ipc_supported_mask & BIT(i))) 225 continue; 226 227 if (i == ipc_type) 228 marker = "Requested"; 229 else 230 marker = "Fallback"; 231 232 dev_info(dev, "- ipc type %d (%s):\n", i, marker); 233 if (base_profile->fw_path_postfix) 234 dev_info(dev, " Firmware file: %s/%s/%s\n", 235 desc->default_fw_path[i], 236 base_profile->fw_path_postfix, 237 desc->default_fw_filename[i]); 238 else 239 dev_info(dev, " Firmware file: %s/%s\n", 240 desc->default_fw_path[i], 241 desc->default_fw_filename[i]); 242 243 dev_info(dev, " Topology file: %s/%s\n", 244 desc->default_tplg_path[i], 245 plat_data->tplg_filename); 246 } 247 248 if (base_profile->fw_path || base_profile->fw_name || 249 base_profile->tplg_path || base_profile->tplg_name) 250 dev_info(dev, "Verify the path/name override module parameters.\n"); 251 252 dev_info(dev, "Check if you have 'sof-firmware' package installed.\n"); 253 dev_info(dev, "Optionally it can be manually downloaded from:\n"); 254 dev_info(dev, " https://github.com/thesofproject/sof-bin/\n"); 255 } 256 257 static void sof_print_profile_info(struct snd_sof_dev *sdev, 258 enum sof_ipc_type ipc_type, 259 struct sof_loadable_file_profile *profile) 260 { 261 struct device *dev = sdev->dev; 262 263 if (ipc_type != profile->ipc_type) 264 dev_info(dev, 265 "Using fallback IPC type %d (requested type was %d)\n", 266 profile->ipc_type, ipc_type); 267 268 dev_info(dev, "Firmware paths/files for ipc type %d:\n", profile->ipc_type); 269 270 dev_info(dev, " Firmware file: %s/%s\n", profile->fw_path, profile->fw_name); 271 if (profile->fw_lib_path) 272 dev_info(dev, " Firmware lib path: %s\n", profile->fw_lib_path); 273 dev_info(dev, " Topology file: %s/%s\n", profile->tplg_path, profile->tplg_name); 274 } 275 276 int sof_create_ipc_file_profile(struct snd_sof_dev *sdev, 277 struct sof_loadable_file_profile *base_profile, 278 struct sof_loadable_file_profile *out_profile) 279 { 280 const struct sof_dev_desc *desc = sdev->pdata->desc; 281 int ipc_fallback_start, ret, i; 282 283 memset(out_profile, 0, sizeof(*out_profile)); 284 285 ret = sof_file_profile_for_ipc_type(sdev, base_profile->ipc_type, desc, 286 base_profile, out_profile); 287 if (!ret) 288 goto out; 289 290 /* 291 * No firmware file was found for the requested IPC type, as fallback 292 * if SND_SOC_SOF_ALLOW_FALLBACK_TO_NEWER_IPC_VERSION is selected, check 293 * all IPC versions in a backwards direction (from newer to older) 294 * if SND_SOC_SOF_ALLOW_FALLBACK_TO_NEWER_IPC_VERSION is not selected, 295 * check only older IPC versions than the selected/default version 296 */ 297 if (IS_ENABLED(CONFIG_SND_SOC_SOF_ALLOW_FALLBACK_TO_NEWER_IPC_VERSION)) 298 ipc_fallback_start = SOF_IPC_TYPE_COUNT - 1; 299 else 300 ipc_fallback_start = (int)base_profile->ipc_type - 1; 301 302 for (i = ipc_fallback_start; i >= 0 ; i--) { 303 if (i == base_profile->ipc_type || 304 !(desc->ipc_supported_mask & BIT(i))) 305 continue; 306 307 ret = sof_file_profile_for_ipc_type(sdev, i, desc, base_profile, 308 out_profile); 309 if (!ret) 310 break; 311 } 312 313 out: 314 if (ret) 315 sof_print_missing_firmware_info(sdev, base_profile->ipc_type, 316 base_profile); 317 else 318 sof_print_profile_info(sdev, base_profile->ipc_type, out_profile); 319 320 return ret; 321 } 322 EXPORT_SYMBOL(sof_create_ipc_file_profile); 323