summaryrefslogtreecommitdiff
path: root/sound/soc/fsl/fsl_dsp_library_load.c
diff options
context:
space:
mode:
authorDaniel Baluta <daniel.baluta@nxp.com>2018-10-03 19:27:58 +0300
committerDong Aisheng <aisheng.dong@nxp.com>2019-11-25 15:51:57 +0800
commit93bc6108aa6708b411d28302dea98029a6acb5e1 (patch)
tree7bbf17f2708be4b67d2bd874cd7fd14853a5e800 /sound/soc/fsl/fsl_dsp_library_load.c
parentd2164cd4e6df01e34502d13785f5d38001062a53 (diff)
MLK-18497-6: ASoC: fsl: dsp: Add Xtensa library handling API
This is based on RF-2016.4-linux package received from Cadence and introduce the API for loading shared libraries into memory. Based on this we create xf_load_lib/xf_load_unlib functions which are used to tell DSP framework that codec libraries are mapped in memory and it can start using them. Reviewed-by: Cosmin-Gabriel Samoila <cosmin.samoila@nxp.com> Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
Diffstat (limited to 'sound/soc/fsl/fsl_dsp_library_load.c')
-rw-r--r--sound/soc/fsl/fsl_dsp_library_load.c645
1 files changed, 645 insertions, 0 deletions
diff --git a/sound/soc/fsl/fsl_dsp_library_load.c b/sound/soc/fsl/fsl_dsp_library_load.c
new file mode 100644
index 000000000000..37bce3a289b5
--- /dev/null
+++ b/sound/soc/fsl/fsl_dsp_library_load.c
@@ -0,0 +1,645 @@
+// SPDX-License-Identifier: GPL-2.0+
+// Copyright 2018 NXP
+// Copyright (c) 2012-2013 by Tensilica Inc.
+
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/elf.h>
+
+#include "fsl_dsp.h"
+#include "fsl_dsp_library_load.h"
+
+static Elf32_Half xtlib_host_half(Elf32_Half v, int byteswap)
+{
+ return (byteswap) ? (v >> 8) | (v << 8) : v;
+}
+
+static Elf32_Word xtlib_host_word(Elf32_Word v, int byteswap)
+{
+ if (byteswap) {
+ v = ((v & 0x00FF00FF) << 8) | ((v & 0xFF00FF00) >> 8);
+ v = (v >> 16) | (v << 16);
+ }
+ return v;
+}
+
+static int xtlib_verify_magic(Elf32_Ehdr *header,
+ struct lib_info *lib_info)
+{
+ struct xtlib_loader_globals *xtlib_globals =
+ &lib_info->xtlib_globals;
+ Elf32_Byte magic_no;
+
+ magic_no = header->e_ident[EI_MAG0];
+ if (magic_no != 0x7f)
+ return -1;
+
+ magic_no = header->e_ident[EI_MAG1];
+ if (magic_no != 'E')
+ return -1;
+
+ magic_no = header->e_ident[EI_MAG2];
+ if (magic_no != 'L')
+ return -1;
+
+ magic_no = header->e_ident[EI_MAG3];
+ if (magic_no != 'F')
+ return -1;
+
+ if (header->e_ident[EI_CLASS] != ELFCLASS32)
+ return -1;
+
+ {
+ /* determine byte order */
+ union {
+ short s;
+ char c[sizeof(short)];
+ } u;
+
+ u.s = 1;
+
+ if (header->e_ident[EI_DATA] == ELFDATA2LSB)
+ xtlib_globals->byteswap = u.c[sizeof(short) - 1] == 1;
+ else if (header->e_ident[EI_DATA] == ELFDATA2MSB)
+ xtlib_globals->byteswap = u.c[0] == 1;
+ else
+ return -1;
+ }
+
+ return 0;
+}
+
+static void xtlib_load_seg(Elf32_Phdr *pheader, void *src_addr, xt_ptr dst_addr,
+ struct lib_info *lib_info)
+{
+ struct xtlib_loader_globals *xtlib_globals =
+ &lib_info->xtlib_globals;
+ Elf32_Word bytes_to_copy = xtlib_host_word(pheader->p_filesz,
+ xtlib_globals->byteswap);
+ Elf32_Word bytes_to_zero = xtlib_host_word(pheader->p_memsz,
+ xtlib_globals->byteswap)
+ - bytes_to_copy;
+ unsigned int i;
+ char *src_back, *dst_back;
+
+ void *zero_addr = (void *)dst_addr + bytes_to_copy;
+
+ if (bytes_to_copy > 0) {
+ // memcpy((void *)(dst_addr), src_addr, bytes_to_copy);
+ src_back = (char *)src_addr;
+ dst_back = (char *)dst_addr;
+ for (i = 0; i < bytes_to_copy; i++)
+ *dst_back++ = *src_back++;
+ }
+
+ if (bytes_to_zero > 0) {
+ // memset(zero_addr, 0, bytes_to_zero);
+ dst_back = (char *)zero_addr;
+ for (i = 0; i < bytes_to_zero; i++)
+ *dst_back++ = 0;
+ }
+}
+
+#define xtlib_xt_half xtlib_host_half
+#define xtlib_xt_word xtlib_host_word
+
+static xt_ptr align_ptr(xt_ptr ptr, xt_uint align)
+{
+ return (xt_ptr)(((xt_uint)ptr + align - 1) & ~(align - 1));
+}
+
+static xt_ptr xt_ptr_offs(xt_ptr base, Elf32_Word offs,
+ struct lib_info *lib_info)
+{
+ struct xtlib_loader_globals *xtlib_globals =
+ &lib_info->xtlib_globals;
+
+ return (xt_ptr)xtlib_xt_word((xt_uint)base +
+ xtlib_host_word(offs, xtlib_globals->byteswap),
+ xtlib_globals->byteswap);
+}
+
+static Elf32_Dyn *find_dynamic_info(Elf32_Ehdr *eheader,
+ struct lib_info *lib_info)
+{
+ char *base_addr = (char *)eheader;
+ struct xtlib_loader_globals *xtlib_globals =
+ &lib_info->xtlib_globals;
+ Elf32_Phdr *pheader = (Elf32_Phdr *)(base_addr +
+ xtlib_host_word(eheader->e_phoff,
+ xtlib_globals->byteswap));
+
+ int seg = 0;
+ int num = xtlib_host_half(eheader->e_phnum, xtlib_globals->byteswap);
+
+ while (seg < num) {
+ if (xtlib_host_word(pheader[seg].p_type,
+ xtlib_globals->byteswap) == PT_DYNAMIC) {
+ return (Elf32_Dyn *)(base_addr +
+ xtlib_host_word(pheader[seg].p_offset,
+ xtlib_globals->byteswap));
+ }
+ seg++;
+ }
+ return 0;
+}
+
+static int find_align(Elf32_Ehdr *header,
+ struct lib_info *lib_info)
+{
+ struct xtlib_loader_globals *xtlib_globals =
+ &lib_info->xtlib_globals;
+ Elf32_Shdr *sheader = (Elf32_Shdr *) (((char *)header) +
+ xtlib_host_word(header->e_shoff, xtlib_globals->byteswap));
+
+ int sec = 0;
+ int num = xtlib_host_half(header->e_shnum, xtlib_globals->byteswap);
+
+ int align = 0;
+
+ while (sec < num) {
+ if (sheader[sec].sh_type != SHT_NULL &&
+ xtlib_host_word(sheader[sec].sh_size,
+ xtlib_globals->byteswap) > 0) {
+ int sec_align =
+ xtlib_host_word(sheader[sec].sh_addralign,
+ xtlib_globals->byteswap);
+ if (sec_align > align)
+ align = sec_align;
+ }
+ sec++;
+ }
+
+ return align;
+}
+
+static int validate_dynamic(Elf32_Ehdr *header,
+ struct lib_info *lib_info)
+{
+ struct xtlib_loader_globals *xtlib_globals =
+ &lib_info->xtlib_globals;
+
+ if (xtlib_verify_magic(header, lib_info) != 0)
+ return XTLIB_NOT_ELF;
+
+ if (xtlib_host_half(header->e_type,
+ xtlib_globals->byteswap) != ET_DYN)
+ return XTLIB_NOT_DYNAMIC;
+
+ return XTLIB_NO_ERR;
+}
+
+static int validate_dynamic_splitload(Elf32_Ehdr *header,
+ struct lib_info *lib_info)
+{
+ struct xtlib_loader_globals *xtlib_globals =
+ &lib_info->xtlib_globals;
+ Elf32_Phdr *pheader;
+ int err = validate_dynamic(header, lib_info);
+
+ if (err != XTLIB_NO_ERR)
+ return err;
+
+ /* make sure it's split load pi library, expecting three headers,
+ * code, data and dynamic, for example:
+ *
+ *LOAD off 0x00000094 vaddr 0x00000000 paddr 0x00000000 align 2**0
+ * filesz 0x00000081 memsz 0x00000081 flags r-x
+ *LOAD off 0x00000124 vaddr 0x00000084 paddr 0x00000084 align 2**0
+ * filesz 0x000001ab memsz 0x000011bc flags rwx
+ *DYNAMIC off 0x00000124 vaddr 0x00000084 paddr 0x00000084 align 2**2
+ * filesz 0x000000a0 memsz 0x000000a0 flags rw-
+ */
+
+ if (xtlib_host_half(header->e_phnum, xtlib_globals->byteswap) != 3)
+ return XTLIB_NOT_SPLITLOAD;
+
+ pheader = (Elf32_Phdr *)((char *)header +
+ xtlib_host_word(header->e_phoff, xtlib_globals->byteswap));
+
+ /* LOAD R-X */
+ if (xtlib_host_word(pheader[0].p_type,
+ xtlib_globals->byteswap) != PT_LOAD ||
+ (xtlib_host_word(pheader[0].p_flags,
+ xtlib_globals->byteswap)
+ & (PF_R | PF_W | PF_X)) != (PF_R | PF_X))
+ return XTLIB_NOT_SPLITLOAD;
+
+ /* LOAD RWX */
+ if (xtlib_host_word(pheader[1].p_type,
+ xtlib_globals->byteswap) != PT_LOAD ||
+ (xtlib_host_word(pheader[1].p_flags,
+ xtlib_globals->byteswap)
+ & (PF_R | PF_W | PF_X)) != (PF_R | PF_W | PF_X))
+ return XTLIB_NOT_SPLITLOAD;
+
+ /* DYNAMIC RW- */
+ if (xtlib_host_word(pheader[2].p_type,
+ xtlib_globals->byteswap) != PT_DYNAMIC ||
+ (xtlib_host_word(pheader[2].p_flags,
+ xtlib_globals->byteswap)
+ & (PF_R | PF_W | PF_X)) != (PF_R | PF_W))
+ return XTLIB_NOT_SPLITLOAD;
+
+ return XTLIB_NO_ERR;
+}
+
+static unsigned int
+xtlib_split_pi_library_size(struct xtlib_packaged_library *library,
+ unsigned int *code_size,
+ unsigned int *data_size,
+ struct lib_info *lib_info)
+{
+ struct xtlib_loader_globals *xtlib_globals =
+ &lib_info->xtlib_globals;
+ Elf32_Phdr *pheader;
+ Elf32_Ehdr *header = (Elf32_Ehdr *)library;
+ int align;
+ int err = validate_dynamic_splitload(header, lib_info);
+
+ if (err != XTLIB_NO_ERR) {
+ xtlib_globals->err = err;
+ return err;
+ }
+
+ align = find_align(header, lib_info);
+
+ pheader = (Elf32_Phdr *)((char *)library +
+ xtlib_host_word(header->e_phoff, xtlib_globals->byteswap));
+
+ *code_size = xtlib_host_word(pheader[0].p_memsz,
+ xtlib_globals->byteswap) + align;
+ *data_size = xtlib_host_word(pheader[1].p_memsz,
+ xtlib_globals->byteswap) + align;
+
+ return XTLIB_NO_ERR;
+}
+
+static int get_dyn_info(Elf32_Ehdr *eheader,
+ xt_ptr dst_addr, xt_uint src_offs,
+ xt_ptr dst_data_addr, xt_uint src_data_offs,
+ struct xtlib_pil_info *info,
+ struct lib_info *lib_info)
+{
+ unsigned int jmprel = 0;
+ unsigned int pltrelsz = 0;
+ struct xtlib_loader_globals *xtlib_globals =
+ &lib_info->xtlib_globals;
+ Elf32_Dyn *dyn_entry = find_dynamic_info(eheader, lib_info);
+
+ if (dyn_entry == 0)
+ return XTLIB_NO_DYNAMIC_SEGMENT;
+
+ info->dst_addr = (xt_uint)xtlib_xt_word((Elf32_Word)dst_addr,
+ xtlib_globals->byteswap);
+ info->src_offs = xtlib_xt_word(src_offs, xtlib_globals->byteswap);
+ info->dst_data_addr = (xt_uint)xtlib_xt_word(
+ (Elf32_Word)dst_data_addr + src_data_offs,
+ xtlib_globals->byteswap);
+ info->src_data_offs = xtlib_xt_word(src_data_offs,
+ xtlib_globals->byteswap);
+
+ dst_addr -= src_offs;
+ dst_data_addr = dst_data_addr + src_data_offs - src_data_offs;
+
+ info->start_sym = xt_ptr_offs(dst_addr, eheader->e_entry, lib_info);
+
+ info->align = xtlib_xt_word(find_align(eheader, lib_info),
+ xtlib_globals->byteswap);
+
+ info->text_addr = 0;
+
+ while (dyn_entry->d_tag != DT_NULL) {
+ switch ((Elf32_Sword) xtlib_host_word(
+ (Elf32_Word)dyn_entry->d_tag,
+ xtlib_globals->byteswap)) {
+ case DT_RELA:
+ info->rel = xt_ptr_offs(dst_data_addr,
+ dyn_entry->d_un.d_ptr, lib_info);
+ break;
+ case DT_RELASZ:
+ info->rela_count = xtlib_xt_word(
+ xtlib_host_word(dyn_entry->d_un.d_val,
+ xtlib_globals->byteswap) /
+ sizeof(Elf32_Rela),
+ xtlib_globals->byteswap);
+ break;
+ case DT_INIT:
+ info->init = xt_ptr_offs(dst_addr,
+ dyn_entry->d_un.d_ptr, lib_info);
+ break;
+ case DT_FINI:
+ info->fini = xt_ptr_offs(dst_addr,
+ dyn_entry->d_un.d_ptr, lib_info);
+ break;
+ case DT_HASH:
+ info->hash = xt_ptr_offs(dst_data_addr,
+ dyn_entry->d_un.d_ptr, lib_info);
+ break;
+ case DT_SYMTAB:
+ info->symtab = xt_ptr_offs(dst_data_addr,
+ dyn_entry->d_un.d_ptr, lib_info);
+ break;
+ case DT_STRTAB:
+ info->strtab = xt_ptr_offs(dst_data_addr,
+ dyn_entry->d_un.d_ptr, lib_info);
+ break;
+ case DT_JMPREL:
+ jmprel = dyn_entry->d_un.d_val;
+ break;
+ case DT_PLTRELSZ:
+ pltrelsz = dyn_entry->d_un.d_val;
+ break;
+ case DT_LOPROC + 2:
+ info->text_addr = xt_ptr_offs(dst_addr,
+ dyn_entry->d_un.d_ptr, lib_info);
+ break;
+
+ default:
+ /* do nothing */
+ break;
+ }
+ dyn_entry++;
+ }
+
+ return XTLIB_NO_ERR;
+}
+
+static xt_ptr
+xtlib_load_split_pi_library_common(struct xtlib_packaged_library *library,
+ xt_ptr destination_code_address,
+ xt_ptr destination_data_address,
+ struct xtlib_pil_info *info,
+ struct lib_info *lib_info)
+{
+ struct xtlib_loader_globals *xtlib_globals =
+ &lib_info->xtlib_globals;
+ Elf32_Ehdr *header = (Elf32_Ehdr *)library;
+ Elf32_Phdr *pheader;
+ unsigned int align;
+ int err = validate_dynamic_splitload(header, lib_info);
+ xt_ptr destination_code_address_back;
+ xt_ptr destination_data_address_back;
+
+ if (err != XTLIB_NO_ERR) {
+ xtlib_globals->err = err;
+ return 0;
+ }
+
+ align = find_align(header, lib_info);
+
+ destination_code_address_back = destination_code_address;
+ destination_data_address_back = destination_data_address;
+
+ destination_code_address = align_ptr(destination_code_address, align);
+ destination_data_address = align_ptr(destination_data_address, align);
+ lib_info->code_buf_virt += (destination_code_address -
+ destination_code_address_back);
+ lib_info->data_buf_virt += (destination_data_address -
+ destination_data_address_back);
+
+ pheader = (Elf32_Phdr *)((char *)library +
+ xtlib_host_word(header->e_phoff,
+ xtlib_globals->byteswap));
+
+ err = get_dyn_info(header,
+ destination_code_address,
+ xtlib_host_word(pheader[0].p_paddr,
+ xtlib_globals->byteswap),
+ destination_data_address,
+ xtlib_host_word(pheader[1].p_paddr,
+ xtlib_globals->byteswap),
+ info,
+ lib_info);
+
+ if (err != XTLIB_NO_ERR) {
+ xtlib_globals->err = err;
+ return 0;
+ }
+
+ /* loading code */
+ xtlib_load_seg(&pheader[0],
+ (char *)library + xtlib_host_word(pheader[0].p_offset,
+ xtlib_globals->byteswap),
+ (xt_ptr)lib_info->code_buf_virt,
+ lib_info);
+
+ if (info->text_addr == 0)
+ info->text_addr =
+ (xt_ptr)xtlib_xt_word((Elf32_Word)destination_code_address,
+ xtlib_globals->byteswap);
+
+ /* loading data */
+ xtlib_load_seg(&pheader[1],
+ (char *)library + xtlib_host_word(pheader[1].p_offset,
+ xtlib_globals->byteswap),
+ (xt_ptr)lib_info->data_buf_virt +
+ xtlib_host_word(pheader[1].p_paddr,
+ xtlib_globals->byteswap),
+ lib_info);
+
+ if (err != XTLIB_NO_ERR) {
+ xtlib_globals->err = err;
+ return 0;
+ }
+
+ return (xt_ptr)xtlib_host_word((Elf32_Word)info->start_sym,
+ xtlib_globals->byteswap);
+}
+
+static xt_ptr
+xtlib_host_load_split_pi_library(struct xtlib_packaged_library *library,
+ xt_ptr destination_code_address,
+ xt_ptr destination_data_address,
+ struct xtlib_pil_info *info,
+ struct lib_info *lib_info)
+{
+ return xtlib_load_split_pi_library_common(library,
+ destination_code_address,
+ destination_data_address,
+ info,
+ lib_info);
+}
+
+static long
+load_dpu_with_library(struct xf_client *client, struct xf_proxy *proxy,
+ struct lib_info *lib_info)
+{
+ struct fsl_dsp *dsp_priv = container_of(proxy, struct fsl_dsp, proxy);
+ unsigned char *srambuf;
+ struct lib_dnld_info_t dpulib;
+ struct file *file;
+ struct xf_buffer *buf;
+ Elf32_Phdr *pheader;
+ Elf32_Ehdr *header;
+ loff_t pos = 0;
+ unsigned int align;
+ int filesize = 0;
+ long ret_val = 0;
+
+ file = filp_open(lib_info->filename, O_RDONLY, 0);
+ if (IS_ERR(file))
+ return PTR_ERR(file);
+
+ vfs_llseek(file, 0, SEEK_END);
+ filesize = (int)file->f_pos;
+
+ srambuf = kmalloc(filesize, GFP_KERNEL);
+ if (!srambuf)
+ return -ENOMEM;
+
+ vfs_llseek(file, 0, SEEK_SET);
+ kernel_read(file, srambuf, filesize, &pos);
+ filp_close(file, NULL);
+
+ ret_val = xtlib_split_pi_library_size(
+ (struct xtlib_packaged_library *)(srambuf),
+ (unsigned int *)&dpulib.size_code,
+ (unsigned int *)&dpulib.size_data,
+ lib_info);
+ if (ret_val != XTLIB_NO_ERR)
+ return -EINVAL;
+
+ lib_info->code_buf_size = dpulib.size_code;
+ lib_info->data_buf_size = dpulib.size_data;
+
+ header = (Elf32_Ehdr *)srambuf;
+ pheader = (Elf32_Phdr *)((char *)srambuf +
+ xtlib_host_word(header->e_phoff,
+ lib_info->xtlib_globals.byteswap));
+
+ align = find_align(header, lib_info);
+ ret_val = xf_pool_alloc(client, proxy, 1, dpulib.size_code + align,
+ XF_POOL_AUX, &lib_info->code_section_pool);
+ if (ret_val) {
+ kfree(srambuf);
+ pr_err("Allocation failure for loading code section\n");
+ return -ENOMEM;
+ }
+
+ ret_val = xf_pool_alloc(client, proxy, 1,
+ dpulib.size_data + pheader[1].p_paddr + align,
+ XF_POOL_AUX, &lib_info->data_section_pool);
+ if (ret_val) {
+ kfree(srambuf);
+ pr_err("Allocation failure for loading data section\n");
+ return -ENOMEM;
+ }
+
+ buf = xf_buffer_get(lib_info->code_section_pool);
+ lib_info->code_buf_virt = xf_buffer_data(buf);
+ lib_info->code_buf_phys = ((u64)xf_buffer_data(buf) -
+ (u64)dsp_priv->scratch_buf_virt) +
+ dsp_priv->scratch_buf_phys;
+ lib_info->code_buf_size = dpulib.size_code + align;
+ xf_buffer_put(buf);
+
+ buf = xf_buffer_get(lib_info->data_section_pool);
+ lib_info->data_buf_virt = xf_buffer_data(buf);
+ lib_info->data_buf_phys = ((u64)xf_buffer_data(buf) -
+ (u64)dsp_priv->scratch_buf_virt) +
+ dsp_priv->scratch_buf_phys;
+ lib_info->data_buf_size = dpulib.size_data + align + pheader[1].p_paddr;
+ xf_buffer_put(buf);
+
+ dpulib.pbuf_code = (unsigned long)lib_info->code_buf_phys;
+ dpulib.pbuf_data = (unsigned long)lib_info->data_buf_phys;
+
+ dpulib.ppil_inf = &lib_info->pil_info;
+ xtlib_host_load_split_pi_library((struct xtlib_packaged_library *)srambuf,
+ (xt_ptr)(dpulib.pbuf_code),
+ (xt_ptr)(dpulib.pbuf_data),
+ (struct xtlib_pil_info *)dpulib.ppil_inf,
+ (void *)lib_info);
+ kfree(srambuf);
+
+ return ret_val;
+}
+
+static long
+unload_dpu_with_library(struct xf_client *client, struct xf_proxy *proxy,
+ struct lib_info *lib_info)
+{
+ xf_pool_free(client, lib_info->code_section_pool);
+ xf_pool_free(client, lib_info->data_section_pool);
+
+ return 0;
+}
+
+long xf_load_lib(struct xf_client *client,
+ struct xf_handle *handle, struct lib_info *lib_info)
+{
+ void *b = xf_handle_aux(handle);
+ struct icm_xtlib_pil_info icm_info;
+ struct xf_proxy *proxy = handle->proxy;
+ struct xf_message msg;
+ struct xf_message *rmsg;
+ long ret_val;
+
+ ret_val = load_dpu_with_library(client, proxy, lib_info);
+ if (ret_val)
+ return ret_val;
+
+ memcpy((void *)(&icm_info.pil_info), (void *)(&lib_info->pil_info),
+ sizeof(struct xtlib_pil_info));
+
+ icm_info.lib_type = lib_info->lib_type;
+
+ /* ...set message parameters */
+ msg.id = __XF_MSG_ID(__XF_AP_CLIENT(0, 0), __XF_PORT_SPEC2(handle->id, 0));
+ msg.id = XF_MSG_AP_FROM_USER(msg.id, client->id);
+ msg.opcode = XF_LOAD_LIB;
+ msg.buffer = b;
+ msg.length = sizeof(struct icm_xtlib_pil_info);
+ msg.ret = 0;
+
+ /* ...copy lib info */
+ memcpy(b, (void *)&icm_info, xf_buffer_length(handle->aux));
+
+ /* ...execute command synchronously */
+ rmsg = xf_cmd_send_recv_complete(client, proxy, msg.id, msg.opcode,
+ msg.buffer, msg.length, &client->work,
+ &client->compr_complete);
+ if (IS_ERR(rmsg))
+ return PTR_ERR(rmsg);
+
+// xf_msg_free(proxy, rmsg);
+// xf_unlock(&proxy->lock);
+
+ return 0;
+}
+
+long xf_unload_lib(struct xf_client *client, struct xf_handle *handle, struct lib_info *lib_info)
+{
+ void *b = xf_handle_aux(handle);
+ struct xf_proxy *proxy = handle->proxy;
+ struct xf_message msg;
+ struct xf_message *rmsg;
+ struct icm_xtlib_pil_info icm_info;
+
+ memset((void *)&icm_info, 0, sizeof(struct icm_xtlib_pil_info));
+ icm_info.lib_type = lib_info->lib_type;
+
+ /* ...set message parameters */
+ msg.id = __XF_MSG_ID(__XF_AP_CLIENT(0, 0),__XF_PORT_SPEC2(handle->id, 0));
+ msg.id = XF_MSG_AP_FROM_USER(msg.id, client->id);
+ msg.opcode = XF_UNLOAD_LIB;
+ msg.buffer = b;
+ msg.length = sizeof(struct icm_xtlib_pil_info);
+ msg.ret = 0;
+
+ /* ...copy lib info */
+ memcpy(b, (void *)&icm_info, xf_buffer_length(handle->aux));
+
+ /* ...execute command synchronously */
+ rmsg = xf_cmd_send_recv_complete(client, proxy, msg.id, msg.opcode,
+ msg.buffer, msg.length, &client->work,
+ &client->compr_complete);
+ if (IS_ERR(rmsg))
+ return PTR_ERR(rmsg);
+
+// xf_msg_free(proxy, rmsg);
+// xf_unlock(&proxy->lock);
+
+ return unload_dpu_with_library(client, proxy, lib_info);
+}