0001
0002
0003
0004
0005
0006
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
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
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
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
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
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
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
0232
0233
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
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
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
0275
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
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
0319 smp_mb();
0320 __fifo->in += len;
0321 spin_unlock_irqrestore(lock, flags);
0322
0323 return len;
0324 }