Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 //
0003 // Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
0004 //
0005 // Authors: Cezary Rojewski <cezary.rojewski@intel.com>
0006 //          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
0007 //
0008 
0009 #include <linux/firmware.h>
0010 #include <linux/kfifo.h>
0011 #include <linux/slab.h>
0012 #include "avs.h"
0013 #include "messages.h"
0014 
0015 /* Caller responsible for holding adev->modres_mutex. */
0016 static int avs_module_entry_index(struct avs_dev *adev, const guid_t *uuid)
0017 {
0018     int i;
0019 
0020     for (i = 0; i < adev->mods_info->count; i++) {
0021         struct avs_module_entry *module;
0022 
0023         module = &adev->mods_info->entries[i];
0024         if (guid_equal(&module->uuid, uuid))
0025             return i;
0026     }
0027 
0028     return -ENOENT;
0029 }
0030 
0031 /* Caller responsible for holding adev->modres_mutex. */
0032 static int avs_module_id_entry_index(struct avs_dev *adev, u32 module_id)
0033 {
0034     int i;
0035 
0036     for (i = 0; i < adev->mods_info->count; i++) {
0037         struct avs_module_entry *module;
0038 
0039         module = &adev->mods_info->entries[i];
0040         if (module->module_id == module_id)
0041             return i;
0042     }
0043 
0044     return -ENOENT;
0045 }
0046 
0047 int avs_get_module_entry(struct avs_dev *adev, const guid_t *uuid, struct avs_module_entry *entry)
0048 {
0049     int idx;
0050 
0051     mutex_lock(&adev->modres_mutex);
0052 
0053     idx = avs_module_entry_index(adev, uuid);
0054     if (idx >= 0)
0055         memcpy(entry, &adev->mods_info->entries[idx], sizeof(*entry));
0056 
0057     mutex_unlock(&adev->modres_mutex);
0058     return (idx < 0) ? idx : 0;
0059 }
0060 
0061 int avs_get_module_id_entry(struct avs_dev *adev, u32 module_id, struct avs_module_entry *entry)
0062 {
0063     int idx;
0064 
0065     mutex_lock(&adev->modres_mutex);
0066 
0067     idx = avs_module_id_entry_index(adev, module_id);
0068     if (idx >= 0)
0069         memcpy(entry, &adev->mods_info->entries[idx], sizeof(*entry));
0070 
0071     mutex_unlock(&adev->modres_mutex);
0072     return (idx < 0) ? idx : 0;
0073 }
0074 
0075 int avs_get_module_id(struct avs_dev *adev, const guid_t *uuid)
0076 {
0077     struct avs_module_entry module;
0078     int ret;
0079 
0080     ret = avs_get_module_entry(adev, uuid, &module);
0081     return !ret ? module.module_id : -ENOENT;
0082 }
0083 
0084 bool avs_is_module_ida_empty(struct avs_dev *adev, u32 module_id)
0085 {
0086     bool ret = false;
0087     int idx;
0088 
0089     mutex_lock(&adev->modres_mutex);
0090 
0091     idx = avs_module_id_entry_index(adev, module_id);
0092     if (idx >= 0)
0093         ret = ida_is_empty(adev->mod_idas[idx]);
0094 
0095     mutex_unlock(&adev->modres_mutex);
0096     return ret;
0097 }
0098 
0099 /* Caller responsible for holding adev->modres_mutex. */
0100 static void avs_module_ida_destroy(struct avs_dev *adev)
0101 {
0102     int i = adev->mods_info ? adev->mods_info->count : 0;
0103 
0104     while (i--) {
0105         ida_destroy(adev->mod_idas[i]);
0106         kfree(adev->mod_idas[i]);
0107     }
0108     kfree(adev->mod_idas);
0109 }
0110 
0111 /* Caller responsible for holding adev->modres_mutex. */
0112 static int
0113 avs_module_ida_alloc(struct avs_dev *adev, struct avs_mods_info *newinfo, bool purge)
0114 {
0115     struct avs_mods_info *oldinfo = adev->mods_info;
0116     struct ida **ida_ptrs;
0117     u32 tocopy_count = 0;
0118     int i;
0119 
0120     if (!purge && oldinfo) {
0121         if (oldinfo->count >= newinfo->count)
0122             dev_warn(adev->dev, "refreshing %d modules info with %d\n",
0123                  oldinfo->count, newinfo->count);
0124         tocopy_count = oldinfo->count;
0125     }
0126 
0127     ida_ptrs = kcalloc(newinfo->count, sizeof(*ida_ptrs), GFP_KERNEL);
0128     if (!ida_ptrs)
0129         return -ENOMEM;
0130 
0131     if (tocopy_count)
0132         memcpy(ida_ptrs, adev->mod_idas, tocopy_count * sizeof(*ida_ptrs));
0133 
0134     for (i = tocopy_count; i < newinfo->count; i++) {
0135         ida_ptrs[i] = kzalloc(sizeof(**ida_ptrs), GFP_KERNEL);
0136         if (!ida_ptrs[i]) {
0137             while (i--)
0138                 kfree(ida_ptrs[i]);
0139 
0140             kfree(ida_ptrs);
0141             return -ENOMEM;
0142         }
0143 
0144         ida_init(ida_ptrs[i]);
0145     }
0146 
0147     /* If old elements have been reused, don't wipe them. */
0148     if (tocopy_count)
0149         kfree(adev->mod_idas);
0150     else
0151         avs_module_ida_destroy(adev);
0152 
0153     adev->mod_idas = ida_ptrs;
0154     return 0;
0155 }
0156 
0157 int avs_module_info_init(struct avs_dev *adev, bool purge)
0158 {
0159     struct avs_mods_info *info;
0160     int ret;
0161 
0162     ret = avs_ipc_get_modules_info(adev, &info);
0163     if (ret)
0164         return AVS_IPC_RET(ret);
0165 
0166     mutex_lock(&adev->modres_mutex);
0167 
0168     ret = avs_module_ida_alloc(adev, info, purge);
0169     if (ret < 0) {
0170         dev_err(adev->dev, "initialize module idas failed: %d\n", ret);
0171         goto exit;
0172     }
0173 
0174     /* Refresh current information with newly received table. */
0175     kfree(adev->mods_info);
0176     adev->mods_info = info;
0177 
0178 exit:
0179     mutex_unlock(&adev->modres_mutex);
0180     return ret;
0181 }
0182 
0183 void avs_module_info_free(struct avs_dev *adev)
0184 {
0185     mutex_lock(&adev->modres_mutex);
0186 
0187     avs_module_ida_destroy(adev);
0188     kfree(adev->mods_info);
0189     adev->mods_info = NULL;
0190 
0191     mutex_unlock(&adev->modres_mutex);
0192 }
0193 
0194 int avs_module_id_alloc(struct avs_dev *adev, u16 module_id)
0195 {
0196     int ret, idx, max_id;
0197 
0198     mutex_lock(&adev->modres_mutex);
0199 
0200     idx = avs_module_id_entry_index(adev, module_id);
0201     if (idx == -ENOENT) {
0202         dev_err(adev->dev, "invalid module id: %d", module_id);
0203         ret = -EINVAL;
0204         goto exit;
0205     }
0206     max_id = adev->mods_info->entries[idx].instance_max_count - 1;
0207     ret = ida_alloc_max(adev->mod_idas[idx], max_id, GFP_KERNEL);
0208 exit:
0209     mutex_unlock(&adev->modres_mutex);
0210     return ret;
0211 }
0212 
0213 void avs_module_id_free(struct avs_dev *adev, u16 module_id, u8 instance_id)
0214 {
0215     int idx;
0216 
0217     mutex_lock(&adev->modres_mutex);
0218 
0219     idx = avs_module_id_entry_index(adev, module_id);
0220     if (idx == -ENOENT) {
0221         dev_err(adev->dev, "invalid module id: %d", module_id);
0222         goto exit;
0223     }
0224 
0225     ida_free(adev->mod_idas[idx], instance_id);
0226 exit:
0227     mutex_unlock(&adev->modres_mutex);
0228 }
0229 
0230 /*
0231  * Once driver loads FW it should keep it in memory, so we are not affected
0232  * by FW removal from filesystem or even worse by loading different FW at
0233  * runtime suspend/resume.
0234  */
0235 int avs_request_firmware(struct avs_dev *adev, const struct firmware **fw_p, const char *name)
0236 {
0237     struct avs_fw_entry *entry;
0238     int ret;
0239 
0240     /* first check in list if it is not already loaded */
0241     list_for_each_entry(entry, &adev->fw_list, node) {
0242         if (!strcmp(name, entry->name)) {
0243             *fw_p = entry->fw;
0244             return 0;
0245         }
0246     }
0247 
0248     /* FW is not loaded, let's load it now and add to the list */
0249     entry = kzalloc(sizeof(*entry), GFP_KERNEL);
0250     if (!entry)
0251         return -ENOMEM;
0252 
0253     entry->name = kstrdup(name, GFP_KERNEL);
0254     if (!entry->name) {
0255         kfree(entry);
0256         return -ENOMEM;
0257     }
0258 
0259     ret = request_firmware(&entry->fw, name, adev->dev);
0260     if (ret < 0) {
0261         kfree(entry->name);
0262         kfree(entry);
0263         return ret;
0264     }
0265 
0266     *fw_p = entry->fw;
0267 
0268     list_add_tail(&entry->node, &adev->fw_list);
0269 
0270     return 0;
0271 }
0272 
0273 /*
0274  * Release single FW entry, used to handle errors in functions calling
0275  * avs_request_firmware()
0276  */
0277 void avs_release_last_firmware(struct avs_dev *adev)
0278 {
0279     struct avs_fw_entry *entry;
0280 
0281     entry = list_last_entry(&adev->fw_list, typeof(*entry), node);
0282 
0283     list_del(&entry->node);
0284     release_firmware(entry->fw);
0285     kfree(entry->name);
0286     kfree(entry);
0287 }
0288 
0289 /*
0290  * Release all FW entries, used on driver removal
0291  */
0292 void avs_release_firmwares(struct avs_dev *adev)
0293 {
0294     struct avs_fw_entry *entry, *tmp;
0295 
0296     list_for_each_entry_safe(entry, tmp, &adev->fw_list, node) {
0297         list_del(&entry->node);
0298         release_firmware(entry->fw);
0299         kfree(entry->name);
0300         kfree(entry);
0301     }
0302 }
0303 
0304 unsigned int __kfifo_fromio_locked(struct kfifo *fifo, const void __iomem *src, unsigned int len,
0305                    spinlock_t *lock)
0306 {
0307     struct __kfifo *__fifo = &fifo->kfifo;
0308     unsigned long flags;
0309     unsigned int l, off;
0310 
0311     spin_lock_irqsave(lock, flags);
0312     len = min(len, kfifo_avail(fifo));
0313     off = __fifo->in & __fifo->mask;
0314     l = min(len, kfifo_size(fifo) - off);
0315 
0316     memcpy_fromio(__fifo->data + off, src, l);
0317     memcpy_fromio(__fifo->data, src + l, len - l);
0318     /* Make sure data copied from SRAM is visible to all CPUs. */
0319     smp_mb();
0320     __fifo->in += len;
0321     spin_unlock_irqrestore(lock, flags);
0322 
0323     return len;
0324 }