1 // SPDX-License-Identifier: GPL-2.0-only
3 // Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
5 // Authors: Cezary Rojewski <cezary.rojewski@intel.com>
6 // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
9 #include <linux/firmware.h>
10 #include <linux/kfifo.h>
11 #include <linux/slab.h>
15 /* Caller responsible for holding adev->modres_mutex. */
16 static int avs_module_entry_index(struct avs_dev *adev, const guid_t *uuid)
20 for (i = 0; i < adev->mods_info->count; i++) {
21 struct avs_module_entry *module;
23 module = &adev->mods_info->entries[i];
24 if (guid_equal(&module->uuid, uuid))
31 /* Caller responsible for holding adev->modres_mutex. */
32 static int avs_module_id_entry_index(struct avs_dev *adev, u32 module_id)
36 for (i = 0; i < adev->mods_info->count; i++) {
37 struct avs_module_entry *module;
39 module = &adev->mods_info->entries[i];
40 if (module->module_id == module_id)
47 int avs_get_module_entry(struct avs_dev *adev, const guid_t *uuid, struct avs_module_entry *entry)
51 mutex_lock(&adev->modres_mutex);
53 idx = avs_module_entry_index(adev, uuid);
55 memcpy(entry, &adev->mods_info->entries[idx], sizeof(*entry));
57 mutex_unlock(&adev->modres_mutex);
58 return (idx < 0) ? idx : 0;
61 int avs_get_module_id_entry(struct avs_dev *adev, u32 module_id, struct avs_module_entry *entry)
65 mutex_lock(&adev->modres_mutex);
67 idx = avs_module_id_entry_index(adev, module_id);
69 memcpy(entry, &adev->mods_info->entries[idx], sizeof(*entry));
71 mutex_unlock(&adev->modres_mutex);
72 return (idx < 0) ? idx : 0;
75 int avs_get_module_id(struct avs_dev *adev, const guid_t *uuid)
77 struct avs_module_entry module;
80 ret = avs_get_module_entry(adev, uuid, &module);
81 return !ret ? module.module_id : -ENOENT;
84 bool avs_is_module_ida_empty(struct avs_dev *adev, u32 module_id)
89 mutex_lock(&adev->modres_mutex);
91 idx = avs_module_id_entry_index(adev, module_id);
93 ret = ida_is_empty(adev->mod_idas[idx]);
95 mutex_unlock(&adev->modres_mutex);
99 /* Caller responsible for holding adev->modres_mutex. */
100 static void avs_module_ida_destroy(struct avs_dev *adev)
102 int i = adev->mods_info ? adev->mods_info->count : 0;
105 ida_destroy(adev->mod_idas[i]);
106 kfree(adev->mod_idas[i]);
108 kfree(adev->mod_idas);
111 /* Caller responsible for holding adev->modres_mutex. */
113 avs_module_ida_alloc(struct avs_dev *adev, struct avs_mods_info *newinfo, bool purge)
115 struct avs_mods_info *oldinfo = adev->mods_info;
116 struct ida **ida_ptrs;
117 u32 tocopy_count = 0;
120 if (!purge && oldinfo) {
121 if (oldinfo->count >= newinfo->count)
122 dev_warn(adev->dev, "refreshing %d modules info with %d\n",
123 oldinfo->count, newinfo->count);
124 tocopy_count = oldinfo->count;
127 ida_ptrs = kcalloc(newinfo->count, sizeof(*ida_ptrs), GFP_KERNEL);
132 memcpy(ida_ptrs, adev->mod_idas, tocopy_count * sizeof(*ida_ptrs));
134 for (i = tocopy_count; i < newinfo->count; i++) {
135 ida_ptrs[i] = kzalloc(sizeof(**ida_ptrs), GFP_KERNEL);
144 ida_init(ida_ptrs[i]);
147 /* If old elements have been reused, don't wipe them. */
149 kfree(adev->mod_idas);
151 avs_module_ida_destroy(adev);
153 adev->mod_idas = ida_ptrs;
157 int avs_module_info_init(struct avs_dev *adev, bool purge)
159 struct avs_mods_info *info;
162 ret = avs_ipc_get_modules_info(adev, &info);
164 return AVS_IPC_RET(ret);
166 mutex_lock(&adev->modres_mutex);
168 ret = avs_module_ida_alloc(adev, info, purge);
170 dev_err(adev->dev, "initialize module idas failed: %d\n", ret);
174 /* Refresh current information with newly received table. */
175 kfree(adev->mods_info);
176 adev->mods_info = info;
179 mutex_unlock(&adev->modres_mutex);
183 void avs_module_info_free(struct avs_dev *adev)
185 mutex_lock(&adev->modres_mutex);
187 avs_module_ida_destroy(adev);
188 kfree(adev->mods_info);
189 adev->mods_info = NULL;
191 mutex_unlock(&adev->modres_mutex);
194 int avs_module_id_alloc(struct avs_dev *adev, u16 module_id)
196 int ret, idx, max_id;
198 mutex_lock(&adev->modres_mutex);
200 idx = avs_module_id_entry_index(adev, module_id);
201 if (idx == -ENOENT) {
202 dev_err(adev->dev, "invalid module id: %d", module_id);
206 max_id = adev->mods_info->entries[idx].instance_max_count - 1;
207 ret = ida_alloc_max(adev->mod_idas[idx], max_id, GFP_KERNEL);
209 mutex_unlock(&adev->modres_mutex);
213 void avs_module_id_free(struct avs_dev *adev, u16 module_id, u8 instance_id)
217 mutex_lock(&adev->modres_mutex);
219 idx = avs_module_id_entry_index(adev, module_id);
220 if (idx == -ENOENT) {
221 dev_err(adev->dev, "invalid module id: %d", module_id);
225 ida_free(adev->mod_idas[idx], instance_id);
227 mutex_unlock(&adev->modres_mutex);
231 * Once driver loads FW it should keep it in memory, so we are not affected
232 * by FW removal from filesystem or even worse by loading different FW at
233 * runtime suspend/resume.
235 int avs_request_firmware(struct avs_dev *adev, const struct firmware **fw_p, const char *name)
237 struct avs_fw_entry *entry;
240 /* first check in list if it is not already loaded */
241 list_for_each_entry(entry, &adev->fw_list, node) {
242 if (!strcmp(name, entry->name)) {
248 /* FW is not loaded, let's load it now and add to the list */
249 entry = kzalloc(sizeof(*entry), GFP_KERNEL);
253 entry->name = kstrdup(name, GFP_KERNEL);
259 ret = request_firmware(&entry->fw, name, adev->dev);
268 list_add_tail(&entry->node, &adev->fw_list);
274 * Release single FW entry, used to handle errors in functions calling
275 * avs_request_firmware()
277 void avs_release_last_firmware(struct avs_dev *adev)
279 struct avs_fw_entry *entry;
281 entry = list_last_entry(&adev->fw_list, typeof(*entry), node);
283 list_del(&entry->node);
284 release_firmware(entry->fw);
290 * Release all FW entries, used on driver removal
292 void avs_release_firmwares(struct avs_dev *adev)
294 struct avs_fw_entry *entry, *tmp;
296 list_for_each_entry_safe(entry, tmp, &adev->fw_list, node) {
297 list_del(&entry->node);
298 release_firmware(entry->fw);
304 unsigned int __kfifo_fromio_locked(struct kfifo *fifo, const void __iomem *src, unsigned int len,
307 struct __kfifo *__fifo = &fifo->kfifo;
311 spin_lock_irqsave(lock, flags);
312 len = min(len, kfifo_avail(fifo));
313 off = __fifo->in & __fifo->mask;
314 l = min(len, kfifo_size(fifo) - off);
316 memcpy_fromio(__fifo->data + off, src, l);
317 memcpy_fromio(__fifo->data, src + l, len - l);
318 /* Make sure data copied from SRAM is visible to all CPUs. */
321 spin_unlock_irqrestore(lock, flags);