diff options
Diffstat (limited to '')
-rw-r--r-- | drivers/staging/tidspbridge/core/io_sm.c | 2245 |
1 files changed, 0 insertions, 2245 deletions
diff --git a/drivers/staging/tidspbridge/core/io_sm.c b/drivers/staging/tidspbridge/core/io_sm.c deleted file mode 100644 index c2829aa7780f..000000000000 --- a/drivers/staging/tidspbridge/core/io_sm.c +++ /dev/null @@ -1,2245 +0,0 @@ -/* - * io_sm.c - * - * DSP-BIOS Bridge driver support functions for TI OMAP processors. - * - * IO dispatcher for a shared memory channel driver. - * - * Copyright (C) 2005-2006 Texas Instruments, Inc. - * - * This package is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - */ - -/* - * Channel Invariant: - * There is an important invariant condition which must be maintained per - * channel outside of bridge_chnl_get_ioc() and IO_Dispatch(), violation of - * which may cause timeouts and/or failure of the sync_wait_on_event - * function. - */ -#include <linux/types.h> -#include <linux/list.h> - -/* Host OS */ -#include <dspbridge/host_os.h> -#include <linux/workqueue.h> - -/* ----------------------------------- DSP/BIOS Bridge */ -#include <dspbridge/dbdefs.h> - -/* Services Layer */ -#include <dspbridge/ntfy.h> -#include <dspbridge/sync.h> - -/* Hardware Abstraction Layer */ -#include <hw_defs.h> -#include <hw_mmu.h> - -/* Bridge Driver */ -#include <dspbridge/dspdeh.h> -#include <dspbridge/dspio.h> -#include <dspbridge/dspioctl.h> -#include <dspbridge/wdt.h> -#include <_tiomap.h> -#include <tiomap_io.h> -#include <_tiomap_pwr.h> - -/* Platform Manager */ -#include <dspbridge/cod.h> -#include <dspbridge/node.h> -#include <dspbridge/dev.h> - -/* Others */ -#include <dspbridge/rms_sh.h> -#include <dspbridge/mgr.h> -#include <dspbridge/drv.h> -#include "_cmm.h" -#include "module_list.h" - -/* This */ -#include <dspbridge/io_sm.h> -#include "_msg_sm.h" - -/* Defines, Data Structures, Typedefs */ -#define OUTPUTNOTREADY 0xffff -#define NOTENABLED 0xffff /* Channel(s) not enabled */ - -#define EXTEND "_EXT_END" - -#define SWAP_WORD(x) (x) -#define UL_PAGE_ALIGN_SIZE 0x10000 /* Page Align Size */ - -#define MAX_PM_REQS 32 - -#define MMU_FAULT_HEAD1 0xa5a5a5a5 -#define MMU_FAULT_HEAD2 0x96969696 -#define POLL_MAX 1000 -#define MAX_MMU_DBGBUFF 10240 - -/* IO Manager: only one created per board */ -struct io_mgr { - /* These four fields must be the first fields in a io_mgr_ struct */ - /* Bridge device context */ - struct bridge_dev_context *bridge_context; - /* Function interface to Bridge driver */ - struct bridge_drv_interface *intf_fxns; - struct dev_object *dev_obj; /* Device this board represents */ - - /* These fields initialized in bridge_io_create() */ - struct chnl_mgr *chnl_mgr; - struct shm *shared_mem; /* Shared Memory control */ - u8 *input; /* Address of input channel */ - u8 *output; /* Address of output channel */ - struct msg_mgr *msg_mgr; /* Message manager */ - /* Msg control for from DSP messages */ - struct msg_ctrl *msg_input_ctrl; - /* Msg control for to DSP messages */ - struct msg_ctrl *msg_output_ctrl; - u8 *msg_input; /* Address of input messages */ - u8 *msg_output; /* Address of output messages */ - u32 sm_buf_size; /* Size of a shared memory I/O channel */ - bool shared_irq; /* Is this IRQ shared? */ - u32 word_size; /* Size in bytes of DSP word */ - u16 intr_val; /* Interrupt value */ - /* Private extnd proc info; mmu setup */ - struct mgr_processorextinfo ext_proc_info; - struct cmm_object *cmm_mgr; /* Shared Mem Mngr */ - struct work_struct io_workq; /* workqueue */ -#if defined(CONFIG_TIDSPBRIDGE_BACKTRACE) - u32 trace_buffer_begin; /* Trace message start address */ - u32 trace_buffer_end; /* Trace message end address */ - u32 trace_buffer_current; /* Trace message current address */ - u32 gpp_read_pointer; /* GPP Read pointer to Trace buffer */ - u8 *msg; - u32 gpp_va; - u32 dsp_va; -#endif - /* IO Dpc */ - u32 dpc_req; /* Number of requested DPC's. */ - u32 dpc_sched; /* Number of executed DPC's. */ - struct tasklet_struct dpc_tasklet; - spinlock_t dpc_lock; - -}; - -struct shm_symbol_val { - u32 shm_base; - u32 shm_lim; - u32 msg_base; - u32 msg_lim; - u32 shm0_end; - u32 dyn_ext; - u32 ext_end; -}; - -/* Function Prototypes */ -static void io_dispatch_pm(struct io_mgr *pio_mgr); -static void notify_chnl_complete(struct chnl_object *pchnl, - struct chnl_irp *chnl_packet_obj); -static void input_chnl(struct io_mgr *pio_mgr, struct chnl_object *pchnl, - u8 io_mode); -static void output_chnl(struct io_mgr *pio_mgr, struct chnl_object *pchnl, - u8 io_mode); -static void input_msg(struct io_mgr *pio_mgr, struct msg_mgr *hmsg_mgr); -static void output_msg(struct io_mgr *pio_mgr, struct msg_mgr *hmsg_mgr); -static u32 find_ready_output(struct chnl_mgr *chnl_mgr_obj, - struct chnl_object *pchnl, u32 mask); - -/* Bus Addr (cached kernel) */ -static int register_shm_segs(struct io_mgr *hio_mgr, - struct cod_manager *cod_man, - u32 dw_gpp_base_pa); - -static inline void set_chnl_free(struct shm *sm, u32 chnl) -{ - sm->host_free_mask &= ~(1 << chnl); -} - -static inline void set_chnl_busy(struct shm *sm, u32 chnl) -{ - sm->host_free_mask |= 1 << chnl; -} - - -/* - * ======== bridge_io_create ======== - * Create an IO manager object. - */ -int bridge_io_create(struct io_mgr **io_man, - struct dev_object *hdev_obj, - const struct io_attrs *mgr_attrts) -{ - struct io_mgr *pio_mgr = NULL; - struct bridge_dev_context *hbridge_context = NULL; - struct cfg_devnode *dev_node_obj; - struct chnl_mgr *hchnl_mgr; - u8 dev_type; - - /* Check requirements */ - if (!io_man || !mgr_attrts || mgr_attrts->word_size == 0) - return -EFAULT; - - *io_man = NULL; - - dev_get_chnl_mgr(hdev_obj, &hchnl_mgr); - if (!hchnl_mgr || hchnl_mgr->iomgr) - return -EFAULT; - - /* - * Message manager will be created when a file is loaded, since - * size of message buffer in shared memory is configurable in - * the base image. - */ - dev_get_bridge_context(hdev_obj, &hbridge_context); - if (!hbridge_context) - return -EFAULT; - - dev_get_dev_type(hdev_obj, &dev_type); - - /* Allocate IO manager object */ - pio_mgr = kzalloc(sizeof(struct io_mgr), GFP_KERNEL); - if (!pio_mgr) - return -ENOMEM; - - /* Initialize chnl_mgr object */ - pio_mgr->chnl_mgr = hchnl_mgr; - pio_mgr->word_size = mgr_attrts->word_size; - - if (dev_type == DSP_UNIT) { - /* Create an IO DPC */ - tasklet_init(&pio_mgr->dpc_tasklet, io_dpc, (u32) pio_mgr); - - /* Initialize DPC counters */ - pio_mgr->dpc_req = 0; - pio_mgr->dpc_sched = 0; - - spin_lock_init(&pio_mgr->dpc_lock); - - if (dev_get_dev_node(hdev_obj, &dev_node_obj)) { - bridge_io_destroy(pio_mgr); - return -EIO; - } - } - - pio_mgr->bridge_context = hbridge_context; - pio_mgr->shared_irq = mgr_attrts->irq_shared; - if (dsp_wdt_init()) { - bridge_io_destroy(pio_mgr); - return -EPERM; - } - - /* Return IO manager object to caller... */ - hchnl_mgr->iomgr = pio_mgr; - *io_man = pio_mgr; - - return 0; -} - -/* - * ======== bridge_io_destroy ======== - * Purpose: - * Disable interrupts, destroy the IO manager. - */ -int bridge_io_destroy(struct io_mgr *hio_mgr) -{ - int status = 0; - if (hio_mgr) { - /* Free IO DPC object */ - tasklet_kill(&hio_mgr->dpc_tasklet); - -#if defined(CONFIG_TIDSPBRIDGE_BACKTRACE) - kfree(hio_mgr->msg); -#endif - dsp_wdt_exit(); - /* Free this IO manager object */ - kfree(hio_mgr); - } else { - status = -EFAULT; - } - - return status; -} - -struct shm_symbol_val *_get_shm_symbol_values(struct io_mgr *hio_mgr) -{ - struct shm_symbol_val *s; - struct cod_manager *cod_man; - int status; - - s = kzalloc(sizeof(*s), GFP_KERNEL); - if (!s) - return ERR_PTR(-ENOMEM); - - status = dev_get_cod_mgr(hio_mgr->dev_obj, &cod_man); - if (status) - goto free_symbol; - - /* Get start and length of channel part of shared memory */ - status = cod_get_sym_value(cod_man, CHNL_SHARED_BUFFER_BASE_SYM, - &s->shm_base); - if (status) - goto free_symbol; - - status = cod_get_sym_value(cod_man, CHNL_SHARED_BUFFER_LIMIT_SYM, - &s->shm_lim); - if (status) - goto free_symbol; - - if (s->shm_lim <= s->shm_base) { - status = -EINVAL; - goto free_symbol; - } - - /* Get start and length of message part of shared memory */ - status = cod_get_sym_value(cod_man, MSG_SHARED_BUFFER_BASE_SYM, - &s->msg_base); - if (status) - goto free_symbol; - - status = cod_get_sym_value(cod_man, MSG_SHARED_BUFFER_LIMIT_SYM, - &s->msg_lim); - if (status) - goto free_symbol; - - if (s->msg_lim <= s->msg_base) { - status = -EINVAL; - goto free_symbol; - } - -#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE - status = cod_get_sym_value(cod_man, DSP_TRACESEC_END, &s->shm0_end); -#else - status = cod_get_sym_value(cod_man, SHM0_SHARED_END_SYM, &s->shm0_end); -#endif - if (status) - goto free_symbol; - - status = cod_get_sym_value(cod_man, DYNEXTBASE, &s->dyn_ext); - if (status) - goto free_symbol; - - status = cod_get_sym_value(cod_man, EXTEND, &s->ext_end); - if (status) - goto free_symbol; - - return s; - -free_symbol: - kfree(s); - return ERR_PTR(status); -} - -/* - * ======== bridge_io_on_loaded ======== - * Purpose: - * Called when a new program is loaded to get shared memory buffer - * parameters from COFF file. ulSharedBufferBase and ulSharedBufferLimit - * are in DSP address units. - */ -int bridge_io_on_loaded(struct io_mgr *hio_mgr) -{ - struct bridge_dev_context *dc = hio_mgr->bridge_context; - struct cfg_hostres *cfg_res = dc->resources; - struct bridge_ioctl_extproc *eproc; - struct cod_manager *cod_man; - struct chnl_mgr *hchnl_mgr; - struct msg_mgr *hmsg_mgr; - struct shm_symbol_val *s; - int status; - u8 num_procs; - s32 ndx; - u32 i; - u32 mem_sz, msg_sz, pad_sz, shm_sz, shm_base_offs; - u32 seg0_sz, seg1_sz; - u32 pa, va, da; - u32 pa_curr, va_curr, da_curr; - u32 bytes; - u32 all_bits = 0; - u32 page_size[] = { - HW_PAGE_SIZE16MB, HW_PAGE_SIZE1MB, - HW_PAGE_SIZE64KB, HW_PAGE_SIZE4KB - }; - u32 map_attrs = DSP_MAPLITTLEENDIAN | DSP_MAPPHYSICALADDR | - DSP_MAPELEMSIZE32 | DSP_MAPDONOTLOCK; - - status = dev_get_cod_mgr(hio_mgr->dev_obj, &cod_man); - if (status) - return status; - - hchnl_mgr = hio_mgr->chnl_mgr; - - /* The message manager is destroyed when the board is stopped */ - dev_get_msg_mgr(hio_mgr->dev_obj, &hio_mgr->msg_mgr); - hmsg_mgr = hio_mgr->msg_mgr; - if (!hchnl_mgr || !hmsg_mgr) - return -EFAULT; - - if (hio_mgr->shared_mem) - hio_mgr->shared_mem = NULL; - - s = _get_shm_symbol_values(hio_mgr); - if (IS_ERR(s)) - return PTR_ERR(s); - - /* Get total length in bytes */ - shm_sz = (s->shm_lim - s->shm_base + 1) * hio_mgr->word_size; - - /* Calculate size of a PROCCOPY shared memory region */ - dev_dbg(bridge, "%s: (proc)proccopy shmmem size: 0x%x bytes\n", - __func__, shm_sz - sizeof(struct shm)); - - /* Length (bytes) of messaging part of shared memory */ - msg_sz = (s->msg_lim - s->msg_base + 1) * hio_mgr->word_size; - - /* Total length (bytes) of shared memory: chnl + msg */ - mem_sz = shm_sz + msg_sz; - - /* Get memory reserved in host resources */ - (void)mgr_enum_processor_info(0, - (struct dsp_processorinfo *) - &hio_mgr->ext_proc_info, - sizeof(struct mgr_processorextinfo), - &num_procs); - - /* IO supports only one DSP for now */ - if (num_procs != 1) { - status = -EINVAL; - goto free_symbol; - } - - /* The first MMU TLB entry(TLB_0) in DCD is ShmBase */ - pa = cfg_res->mem_phys[1]; - va = cfg_res->mem_base[1]; - - /* This is the virtual uncached ioremapped address!!! */ - /* Why can't we directly take the DSPVA from the symbols? */ - da = hio_mgr->ext_proc_info.ty_tlb[0].dsp_virt; - seg0_sz = (s->shm0_end - da) * hio_mgr->word_size; - seg1_sz = (s->ext_end - s->dyn_ext) * hio_mgr->word_size; - - /* 4K align */ - seg1_sz = (seg1_sz + 0xFFF) & (~0xFFFUL); - - /* 64K align */ - seg0_sz = (seg0_sz + 0xFFFF) & (~0xFFFFUL); - - pad_sz = UL_PAGE_ALIGN_SIZE - ((pa + seg1_sz) % UL_PAGE_ALIGN_SIZE); - if (pad_sz == UL_PAGE_ALIGN_SIZE) - pad_sz = 0x0; - - dev_dbg(bridge, "%s: pa %x, va %x, da %x\n", __func__, pa, va, da); - dev_dbg(bridge, - "shm0_end %x, dyn_ext %x, ext_end %x, seg0_sz %x seg1_sz %x\n", - s->shm0_end, s->dyn_ext, s->ext_end, seg0_sz, seg1_sz); - - if ((seg0_sz + seg1_sz + pad_sz) > cfg_res->mem_length[1]) { - pr_err("%s: shm Error, reserved 0x%x required 0x%x\n", - __func__, cfg_res->mem_length[1], - seg0_sz + seg1_sz + pad_sz); - status = -ENOMEM; - goto free_symbol; - } - - pa_curr = pa; - va_curr = s->dyn_ext * hio_mgr->word_size; - da_curr = va; - bytes = seg1_sz; - - /* - * Try to fit into TLB entries. If not possible, push them to page - * tables. It is quite possible that if sections are not on - * bigger page boundary, we may end up making several small pages. - * So, push them onto page tables, if that is the case. - */ - while (bytes) { - /* - * To find the max. page size with which both PA & VA are - * aligned. - */ - all_bits = pa_curr | va_curr; - dev_dbg(bridge, - "seg all_bits %x, pa_curr %x, va_curr %x, bytes %x\n", - all_bits, pa_curr, va_curr, bytes); - - for (i = 0; i < 4; i++) { - if ((bytes >= page_size[i]) && - ((all_bits & (page_size[i] - 1)) == 0)) { - status = hio_mgr->intf_fxns->brd_mem_map(dc, - pa_curr, va_curr, - page_size[i], map_attrs, - NULL); - if (status) - goto free_symbol; - - pa_curr += page_size[i]; - va_curr += page_size[i]; - da_curr += page_size[i]; - bytes -= page_size[i]; - /* - * Don't try smaller sizes. Hopefully we have - * reached an address aligned to a bigger page - * size. - */ - break; - } - } - } - - pa_curr += pad_sz; - va_curr += pad_sz; - da_curr += pad_sz; - bytes = seg0_sz; - va_curr = da * hio_mgr->word_size; - - eproc = kzalloc(sizeof(*eproc) * BRDIOCTL_NUMOFMMUTLB, GFP_KERNEL); - if (!eproc) { - status = -ENOMEM; - goto free_symbol; - } - - ndx = 0; - /* Configure the TLB entries for the next cacheable segment */ - while (bytes) { - /* - * To find the max. page size with which both PA & VA are - * aligned. - */ - all_bits = pa_curr | va_curr; - dev_dbg(bridge, - "seg1 all_bits %x, pa_curr %x, va_curr %x, bytes %x\n", - all_bits, pa_curr, va_curr, bytes); - - for (i = 0; i < 4; i++) { - if (!(bytes >= page_size[i]) || - !((all_bits & (page_size[i] - 1)) == 0)) - continue; - - if (ndx >= MAX_LOCK_TLB_ENTRIES) { - status = hio_mgr->intf_fxns->brd_mem_map(dc, - pa_curr, va_curr, - page_size[i], map_attrs, - NULL); - dev_dbg(bridge, - "PTE pa %x va %x dsp_va %x sz %x\n", - eproc[ndx].gpp_pa, - eproc[ndx].gpp_va, - eproc[ndx].dsp_va * - hio_mgr->word_size, page_size[i]); - if (status) - goto free_eproc; - } - - /* This is the physical address written to DSP MMU */ - eproc[ndx].gpp_pa = pa_curr; - - /* - * This is the virtual uncached ioremapped - * address!!! - */ - eproc[ndx].gpp_va = da_curr; - eproc[ndx].dsp_va = va_curr / hio_mgr->word_size; - eproc[ndx].size = page_size[i]; - eproc[ndx].endianism = HW_LITTLE_ENDIAN; - eproc[ndx].elem_size = HW_ELEM_SIZE16BIT; - eproc[ndx].mixed_mode = HW_MMU_CPUES; - dev_dbg(bridge, "%s: tlb pa %x va %x dsp_va %x sz %x\n", - __func__, eproc[ndx].gpp_pa, - eproc[ndx].gpp_va, - eproc[ndx].dsp_va * hio_mgr->word_size, - page_size[i]); - ndx++; - - pa_curr += page_size[i]; - va_curr += page_size[i]; - da_curr += page_size[i]; - bytes -= page_size[i]; - /* - * Don't try smaller sizes. Hopefully we have reached - * an address aligned to a bigger page size. - */ - break; - } - } - - /* - * Copy remaining entries from CDB. All entries are 1 MB and - * should not conflict with shm entries on MPU or DSP side. - */ - for (i = 3; i < 7 && ndx < BRDIOCTL_NUMOFMMUTLB; i++) { - struct mgr_processorextinfo *ep = &hio_mgr->ext_proc_info; - u32 word_sz = hio_mgr->word_size; - - if (ep->ty_tlb[i].gpp_phys == 0) - continue; - - if ((ep->ty_tlb[i].gpp_phys > pa - 0x100000 && - ep->ty_tlb[i].gpp_phys <= pa + seg0_sz) || - (ep->ty_tlb[i].dsp_virt > da - 0x100000 / word_sz && - ep->ty_tlb[i].dsp_virt <= da + seg0_sz / word_sz)) { - dev_dbg(bridge, - "err cdb%d pa %x da %x shm pa %x da %x sz %x\n", - i, ep->ty_tlb[i].gpp_phys, - ep->ty_tlb[i].dsp_virt, pa, da, seg0_sz); - status = -EPERM; - goto free_eproc; - } - - if (ndx >= MAX_LOCK_TLB_ENTRIES) { - status = hio_mgr->intf_fxns->brd_mem_map(dc, - ep->ty_tlb[i].gpp_phys, - ep->ty_tlb[i].dsp_virt, - 0x100000, map_attrs, NULL); - if (status) - goto free_eproc; - } - - eproc[ndx].dsp_va = ep->ty_tlb[i].dsp_virt; - eproc[ndx].gpp_pa = ep->ty_tlb[i].gpp_phys; - eproc[ndx].gpp_va = 0; - - /* 1 MB */ - eproc[ndx].size = 0x100000; - dev_dbg(bridge, "shm MMU entry pa %x da 0x%x\n", - eproc[ndx].gpp_pa, eproc[ndx].dsp_va); - ndx++; - } - - /* Map the L4 peripherals */ - i = 0; - while (l4_peripheral_table[i].phys_addr) { - status = hio_mgr->intf_fxns->brd_mem_map(dc, - l4_peripheral_table[i].phys_addr, - l4_peripheral_table[i].dsp_virt_addr, - HW_PAGE_SIZE4KB, map_attrs, NULL); - if (status) - goto free_eproc; - i++; - } - - for (i = ndx; i < BRDIOCTL_NUMOFMMUTLB; i++) { - eproc[i].dsp_va = 0; - eproc[i].gpp_pa = 0; - eproc[i].gpp_va = 0; - eproc[i].size = 0; - } - - /* - * Set the shm physical address entry (grayed out in CDB file) - * to the virtual uncached ioremapped address of shm reserved - * on MPU. - */ - hio_mgr->ext_proc_info.ty_tlb[0].gpp_phys = - (va + seg1_sz + pad_sz); - - /* - * Need shm Phys addr. IO supports only one DSP for now: - * num_procs = 1. - */ - if (!hio_mgr->ext_proc_info.ty_tlb[0].gpp_phys) - return -EFAULT; - - if (eproc[0].dsp_va > s->shm_base) - return -EPERM; - - /* shm_base may not be at ul_dsp_va address */ - shm_base_offs = (s->shm_base - eproc[0].dsp_va) * - hio_mgr->word_size; - /* - * bridge_dev_ctrl() will set dev context dsp-mmu info. In - * bridge_brd_start() the MMU will be re-programed with MMU - * DSPVa-GPPPa pair info while DSP is in a known - * (reset) state. - */ - status = hio_mgr->intf_fxns->dev_cntrl(hio_mgr->bridge_context, - BRDIOCTL_SETMMUCONFIG, eproc); - if (status) - goto free_eproc; - - s->shm_base = hio_mgr->ext_proc_info.ty_tlb[0].gpp_phys; - s->shm_base += shm_base_offs; - s->shm_base = (u32) MEM_LINEAR_ADDRESS((void *)s->shm_base, - mem_sz); - if (!s->shm_base) { - status = -EFAULT; - goto free_eproc; - } - - /* Register SM */ - status = register_shm_segs(hio_mgr, cod_man, eproc[0].gpp_pa); - - hio_mgr->shared_mem = (struct shm *)s->shm_base; - hio_mgr->input = (u8 *) hio_mgr->shared_mem + sizeof(struct shm); - hio_mgr->output = hio_mgr->input + (shm_sz - - sizeof(struct shm)) / 2; - hio_mgr->sm_buf_size = hio_mgr->output - hio_mgr->input; - - /* Set up Shared memory addresses for messaging */ - hio_mgr->msg_input_ctrl = - (struct msg_ctrl *)((u8 *) hio_mgr->shared_mem + shm_sz); - hio_mgr->msg_input = - (u8 *) hio_mgr->msg_input_ctrl + sizeof(struct msg_ctrl); - hio_mgr->msg_output_ctrl = - (struct msg_ctrl *)((u8 *) hio_mgr->msg_input_ctrl + - msg_sz / 2); - hio_mgr->msg_output = - (u8 *) hio_mgr->msg_output_ctrl + sizeof(struct msg_ctrl); - hmsg_mgr->max_msgs = - ((u8 *) hio_mgr->msg_output_ctrl - hio_mgr->msg_input) / - sizeof(struct msg_dspmsg); - - dev_dbg(bridge, "IO MGR shm details: shared_mem %p, input %p, " - "output %p, msg_input_ctrl %p, msg_input %p, " - "msg_output_ctrl %p, msg_output %p\n", - (u8 *) hio_mgr->shared_mem, hio_mgr->input, - hio_mgr->output, (u8 *) hio_mgr->msg_input_ctrl, - hio_mgr->msg_input, (u8 *) hio_mgr->msg_output_ctrl, - hio_mgr->msg_output); - dev_dbg(bridge, "(proc) Mas msgs in shared memory: 0x%x\n", - hmsg_mgr->max_msgs); - memset((void *)hio_mgr->shared_mem, 0, sizeof(struct shm)); - -#if defined(CONFIG_TIDSPBRIDGE_BACKTRACE) - /* Get the start address of trace buffer */ - status = cod_get_sym_value(cod_man, SYS_PUTCBEG, - &hio_mgr->trace_buffer_begin); - if (status) - goto free_eproc; - - hio_mgr->gpp_read_pointer = - hio_mgr->trace_buffer_begin = - (va + seg1_sz + pad_sz) + - (hio_mgr->trace_buffer_begin - da); - - /* Get the end address of trace buffer */ - status = cod_get_sym_value(cod_man, SYS_PUTCEND, - &hio_mgr->trace_buffer_end); - if (status) - goto free_eproc; - - hio_mgr->trace_buffer_end = - (va + seg1_sz + pad_sz) + - (hio_mgr->trace_buffer_end - da); - - /* Get the current address of DSP write pointer */ - status = cod_get_sym_value(cod_man, BRIDGE_SYS_PUTC_CURRENT, - &hio_mgr->trace_buffer_current); - if (status) - goto free_eproc; - - hio_mgr->trace_buffer_current = - (va + seg1_sz + pad_sz) + - (hio_mgr->trace_buffer_current - da); - - /* Calculate the size of trace buffer */ - kfree(hio_mgr->msg); - hio_mgr->msg = kmalloc(((hio_mgr->trace_buffer_end - - hio_mgr->trace_buffer_begin) * - hio_mgr->word_size) + 2, GFP_KERNEL); - if (!hio_mgr->msg) { - status = -ENOMEM; - goto free_eproc; - } - - hio_mgr->dsp_va = da; - hio_mgr->gpp_va = (va + seg1_sz + pad_sz); -#endif - -free_eproc: - kfree(eproc); -free_symbol: - kfree(s); - - return status; -} - -/* - * ======== io_buf_size ======== - * Size of shared memory I/O channel. - */ -u32 io_buf_size(struct io_mgr *hio_mgr) -{ - if (hio_mgr) - return hio_mgr->sm_buf_size; - else - return 0; -} - -/* - * ======== io_cancel_chnl ======== - * Cancel IO on a given PCPY channel. - */ -void io_cancel_chnl(struct io_mgr *hio_mgr, u32 chnl) -{ - struct io_mgr *pio_mgr = (struct io_mgr *)hio_mgr; - struct shm *sm; - - if (!hio_mgr) - goto func_end; - sm = hio_mgr->shared_mem; - - /* Inform DSP that we have no more buffers on this channel */ - set_chnl_free(sm, chnl); - - sm_interrupt_dsp(pio_mgr->bridge_context, MBX_PCPY_CLASS); -func_end: - return; -} - - -/* - * ======== io_dispatch_pm ======== - * Performs I/O dispatch on PM related messages from DSP - */ -static void io_dispatch_pm(struct io_mgr *pio_mgr) -{ - int status; - u32 parg[2]; - - /* Perform Power message processing here */ - parg[0] = pio_mgr->intr_val; - - /* Send the command to the Bridge clk/pwr manager to handle */ - if (parg[0] == MBX_PM_HIBERNATE_EN) { - dev_dbg(bridge, "PM: Hibernate command\n"); - status = pio_mgr->intf_fxns-> - dev_cntrl(pio_mgr->bridge_context, - BRDIOCTL_PWR_HIBERNATE, parg); - if (status) - pr_err("%s: hibernate cmd failed 0x%x\n", - __func__, status); - } else if (parg[0] == MBX_PM_OPP_REQ) { - parg[1] = pio_mgr->shared_mem->opp_request.rqst_opp_pt; - dev_dbg(bridge, "PM: Requested OPP = 0x%x\n", parg[1]); - status = pio_mgr->intf_fxns-> - dev_cntrl(pio_mgr->bridge_context, - BRDIOCTL_CONSTRAINT_REQUEST, parg); - if (status) - dev_dbg(bridge, "PM: Failed to set constraint " - "= 0x%x\n", parg[1]); - } else { - dev_dbg(bridge, "PM: clk control value of msg = 0x%x\n", - parg[0]); - status = pio_mgr->intf_fxns-> - dev_cntrl(pio_mgr->bridge_context, - BRDIOCTL_CLK_CTRL, parg); - if (status) - dev_dbg(bridge, "PM: Failed to ctrl the DSP clk" - "= 0x%x\n", *parg); - } -} - -/* - * ======== io_dpc ======== - * Deferred procedure call for shared memory channel driver ISR. Carries - * out the dispatch of I/O as a non-preemptible event. It can only be - * pre-empted by an ISR. - */ -void io_dpc(unsigned long ref_data) -{ - struct io_mgr *pio_mgr = (struct io_mgr *)ref_data; - struct chnl_mgr *chnl_mgr_obj; - struct msg_mgr *msg_mgr_obj; - struct deh_mgr *hdeh_mgr; - u32 requested; - u32 serviced; - - if (!pio_mgr) - goto func_end; - chnl_mgr_obj = pio_mgr->chnl_mgr; - dev_get_msg_mgr(pio_mgr->dev_obj, &msg_mgr_obj); - dev_get_deh_mgr(pio_mgr->dev_obj, &hdeh_mgr); - if (!chnl_mgr_obj) - goto func_end; - - requested = pio_mgr->dpc_req; - serviced = pio_mgr->dpc_sched; - - if (serviced == requested) - goto func_end; - - /* Process pending DPC's */ - do { - /* Check value of interrupt reg to ensure it's a valid error */ - if ((pio_mgr->intr_val > DEH_BASE) && - (pio_mgr->intr_val < DEH_LIMIT)) { - /* Notify DSP/BIOS exception */ - if (hdeh_mgr) { -#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE - print_dsp_debug_trace(pio_mgr); -#endif - bridge_deh_notify(hdeh_mgr, DSP_SYSERROR, - pio_mgr->intr_val); - } - } - /* Proc-copy channel dispatch */ - input_chnl(pio_mgr, NULL, IO_SERVICE); - output_chnl(pio_mgr, NULL, IO_SERVICE); - -#ifdef CHNL_MESSAGES - if (msg_mgr_obj) { - /* Perform I/O dispatch on message queues */ - input_msg(pio_mgr, msg_mgr_obj); - output_msg(pio_mgr, msg_mgr_obj); - } - -#endif -#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE - if (pio_mgr->intr_val & MBX_DBG_SYSPRINTF) { - /* Notify DSP Trace message */ - print_dsp_debug_trace(pio_mgr); - } -#endif - serviced++; - } while (serviced != requested); - pio_mgr->dpc_sched = requested; -func_end: - return; -} - -/* - * ======== io_mbox_msg ======== - * Main interrupt handler for the shared memory IO manager. - * Calls the Bridge's CHNL_ISR to determine if this interrupt is ours, then - * schedules a DPC to dispatch I/O. - */ -int io_mbox_msg(struct notifier_block *self, unsigned long len, void *msg) -{ - struct io_mgr *pio_mgr; - struct dev_object *dev_obj; - unsigned long flags; - - dev_obj = dev_get_first(); - dev_get_io_mgr(dev_obj, &pio_mgr); - - if (!pio_mgr) - return NOTIFY_BAD; - - pio_mgr->intr_val = (u16)((u32)msg); - if (pio_mgr->intr_val & MBX_PM_CLASS) - io_dispatch_pm(pio_mgr); - - if (pio_mgr->intr_val == MBX_DEH_RESET) { - pio_mgr->intr_val = 0; - } else { - spin_lock_irqsave(&pio_mgr->dpc_lock, flags); - pio_mgr->dpc_req++; - spin_unlock_irqrestore(&pio_mgr->dpc_lock, flags); - tasklet_schedule(&pio_mgr->dpc_tasklet); - } - return NOTIFY_OK; -} - -/* - * ======== io_request_chnl ======== - * Purpose: - * Request channel I/O from the DSP. Sets flags in shared memory, then - * interrupts the DSP. - */ -void io_request_chnl(struct io_mgr *io_manager, struct chnl_object *pchnl, - u8 io_mode, u16 *mbx_val) -{ - struct chnl_mgr *chnl_mgr_obj; - struct shm *sm; - - if (!pchnl || !mbx_val) - goto func_end; - chnl_mgr_obj = io_manager->chnl_mgr; - sm = io_manager->shared_mem; - if (io_mode == IO_INPUT) { - /* Indicate to the DSP we have a buffer available for input */ - set_chnl_busy(sm, pchnl->chnl_id); - *mbx_val = MBX_PCPY_CLASS; - } else if (io_mode == IO_OUTPUT) { - /* - * Record the fact that we have a buffer available for - * output. - */ - chnl_mgr_obj->output_mask |= (1 << pchnl->chnl_id); - } else { - } -func_end: - return; -} - -/* - * ======== iosm_schedule ======== - * Schedule DPC for IO. - */ -void iosm_schedule(struct io_mgr *io_manager) -{ - unsigned long flags; - - if (!io_manager) - return; - - /* Increment count of DPC's pending. */ - spin_lock_irqsave(&io_manager->dpc_lock, flags); - io_manager->dpc_req++; - spin_unlock_irqrestore(&io_manager->dpc_lock, flags); - - /* Schedule DPC */ - tasklet_schedule(&io_manager->dpc_tasklet); -} - -/* - * ======== find_ready_output ======== - * Search for a host output channel which is ready to send. If this is - * called as a result of servicing the DPC, then implement a round - * robin search; otherwise, this was called by a client thread (via - * IO_Dispatch()), so just start searching from the current channel id. - */ -static u32 find_ready_output(struct chnl_mgr *chnl_mgr_obj, - struct chnl_object *pchnl, u32 mask) -{ - u32 ret = OUTPUTNOTREADY; - u32 id, start_id; - u32 shift; - - id = (pchnl != - NULL ? pchnl->chnl_id : (chnl_mgr_obj->last_output + 1)); - id = ((id == CHNL_MAXCHANNELS) ? 0 : id); - if (id >= CHNL_MAXCHANNELS) - goto func_end; - if (mask) { - shift = (1 << id); - start_id = id; - do { - if (mask & shift) { - ret = id; - if (pchnl == NULL) - chnl_mgr_obj->last_output = id; - break; - } - id = id + 1; - id = ((id == CHNL_MAXCHANNELS) ? 0 : id); - shift = (1 << id); - } while (id != start_id); - } -func_end: - return ret; -} - -/* - * ======== input_chnl ======== - * Dispatch a buffer on an input channel. - */ -static void input_chnl(struct io_mgr *pio_mgr, struct chnl_object *pchnl, - u8 io_mode) -{ - struct chnl_mgr *chnl_mgr_obj; - struct shm *sm; - u32 chnl_id; - u32 bytes; - struct chnl_irp *chnl_packet_obj = NULL; - u32 dw_arg; - bool clear_chnl = false; - bool notify_client = false; - - sm = pio_mgr->shared_mem; - chnl_mgr_obj = pio_mgr->chnl_mgr; - - /* Attempt to perform input */ - if (!sm->input_full) - goto func_end; - - bytes = sm->input_size * chnl_mgr_obj->word_size; - chnl_id = sm->input_id; - dw_arg = sm->arg; - if (chnl_id >= CHNL_MAXCHANNELS) { - /* Shouldn't be here: would indicate corrupted shm. */ - goto func_end; - } - pchnl = chnl_mgr_obj->channels[chnl_id]; - if ((pchnl != NULL) && CHNL_IS_INPUT(pchnl->chnl_mode)) { - if ((pchnl->state & ~CHNL_STATEEOS) == CHNL_STATEREADY) { - /* Get the I/O request, and attempt a transfer */ - if (!list_empty(&pchnl->io_requests)) { - if (!pchnl->cio_reqs) - goto func_end; - - chnl_packet_obj = list_first_entry( - &pchnl->io_requests, - struct chnl_irp, link); - list_del(&chnl_packet_obj->link); - pchnl->cio_reqs--; - - /* - * Ensure we don't overflow the client's - * buffer. - */ - bytes = min(bytes, chnl_packet_obj->byte_size); - memcpy(chnl_packet_obj->host_sys_buf, - pio_mgr->input, bytes); - pchnl->bytes_moved += bytes; - chnl_packet_obj->byte_size = bytes; - chnl_packet_obj->arg = dw_arg; - chnl_packet_obj->status = CHNL_IOCSTATCOMPLETE; - - if (bytes == 0) { - /* - * This assertion fails if the DSP - * sends EOS more than once on this - * channel. - */ - if (pchnl->state & CHNL_STATEEOS) - goto func_end; - /* - * Zero bytes indicates EOS. Update - * IOC status for this chirp, and also - * the channel state. - */ - chnl_packet_obj->status |= - CHNL_IOCSTATEOS; - pchnl->state |= CHNL_STATEEOS; - /* - * Notify that end of stream has - * occurred. - */ - ntfy_notify(pchnl->ntfy_obj, - DSP_STREAMDONE); - } - /* Tell DSP if no more I/O buffers available */ - if (list_empty(&pchnl->io_requests)) - set_chnl_free(sm, pchnl->chnl_id); - clear_chnl = true; - notify_client = true; - } else { - /* - * Input full for this channel, but we have no - * buffers available. The channel must be - * "idling". Clear out the physical input - * channel. - */ - clear_chnl = true; - } - } else { - /* Input channel cancelled: clear input channel */ - clear_chnl = true; - } - } else { - /* DPC fired after host closed channel: clear input channel */ - clear_chnl = true; - } - if (clear_chnl) { - /* Indicate to the DSP we have read the input */ - sm->input_full = 0; - sm_interrupt_dsp(pio_mgr->bridge_context, MBX_PCPY_CLASS); - } - if (notify_client) { - /* Notify client with IO completion record */ - notify_chnl_complete(pchnl, chnl_packet_obj); - } -func_end: - return; -} - -/* - * ======== input_msg ======== - * Copies messages from shared memory to the message queues. - */ -static void input_msg(struct io_mgr *pio_mgr, struct msg_mgr *hmsg_mgr) -{ - u32 num_msgs; - u32 i; - u8 *msg_input; - struct msg_queue *msg_queue_obj; - struct msg_frame *pmsg; - struct msg_dspmsg msg; - struct msg_ctrl *msg_ctr_obj; - u32 input_empty; - u32 addr; - - msg_ctr_obj = pio_mgr->msg_input_ctrl; - /* Get the number of input messages to be read */ - input_empty = msg_ctr_obj->buf_empty; - num_msgs = msg_ctr_obj->size; - if (input_empty) - return; - - msg_input = pio_mgr->msg_input; - for (i = 0; i < num_msgs; i++) { - /* Read the next message */ - addr = (u32) &(((struct msg_dspmsg *)msg_input)->msg.cmd); - msg.msg.cmd = - read_ext32_bit_dsp_data(pio_mgr->bridge_context, addr); - addr = (u32) &(((struct msg_dspmsg *)msg_input)->msg.arg1); - msg.msg.arg1 = - read_ext32_bit_dsp_data(pio_mgr->bridge_context, addr); - addr = (u32) &(((struct msg_dspmsg *)msg_input)->msg.arg2); - msg.msg.arg2 = - read_ext32_bit_dsp_data(pio_mgr->bridge_context, addr); - addr = (u32) &(((struct msg_dspmsg *)msg_input)->msgq_id); - msg.msgq_id = - read_ext32_bit_dsp_data(pio_mgr->bridge_context, addr); - msg_input += sizeof(struct msg_dspmsg); - - /* Determine which queue to put the message in */ - dev_dbg(bridge, "input msg: cmd=0x%x arg1=0x%x " - "arg2=0x%x msgq_id=0x%x\n", msg.msg.cmd, - msg.msg.arg1, msg.msg.arg2, msg.msgq_id); - /* - * Interrupt may occur before shared memory and message - * input locations have been set up. If all nodes were - * cleaned up, hmsg_mgr->max_msgs should be 0. - */ - list_for_each_entry(msg_queue_obj, &hmsg_mgr->queue_list, - list_elem) { - if (msg.msgq_id != msg_queue_obj->msgq_id) - continue; - /* Found it */ - if (msg.msg.cmd == RMS_EXITACK) { - /* - * Call the node exit notification. - * The exit message does not get - * queued. - */ - (*hmsg_mgr->on_exit)(msg_queue_obj->arg, - msg.msg.arg1); - break; - } - /* - * Not an exit acknowledgement, queue - * the message. - */ - if (list_empty(&msg_queue_obj->msg_free_list)) { - /* - * No free frame to copy the - * message into. - */ - pr_err("%s: no free msg frames," - " discarding msg\n", - __func__); - break; - } - - pmsg = list_first_entry(&msg_queue_obj->msg_free_list, - struct msg_frame, list_elem); - list_del(&pmsg->list_elem); - pmsg->msg_data = msg; - list_add_tail(&pmsg->list_elem, - &msg_queue_obj->msg_used_list); - ntfy_notify(msg_queue_obj->ntfy_obj, - DSP_NODEMESSAGEREADY); - sync_set_event(msg_queue_obj->sync_event); - } - } - /* Set the post SWI flag */ - if (num_msgs > 0) { - /* Tell the DSP we've read the messages */ - msg_ctr_obj->buf_empty = true; - msg_ctr_obj->post_swi = true; - sm_interrupt_dsp(pio_mgr->bridge_context, MBX_PCPY_CLASS); - } -} - -/* - * ======== notify_chnl_complete ======== - * Purpose: - * Signal the channel event, notifying the client that I/O has completed. - */ -static void notify_chnl_complete(struct chnl_object *pchnl, - struct chnl_irp *chnl_packet_obj) -{ - bool signal_event; - - if (!pchnl || !pchnl->sync_event || !chnl_packet_obj) - goto func_end; - - /* - * Note: we signal the channel event only if the queue of IO - * completions is empty. If it is not empty, the event is sure to be - * signalled by the only IO completion list consumer: - * bridge_chnl_get_ioc(). - */ - signal_event = list_empty(&pchnl->io_completions); - /* Enqueue the IO completion info for the client */ - list_add_tail(&chnl_packet_obj->link, &pchnl->io_completions); - pchnl->cio_cs++; - - if (pchnl->cio_cs > pchnl->chnl_packets) - goto func_end; - /* Signal the channel event (if not already set) that IO is complete */ - if (signal_event) - sync_set_event(pchnl->sync_event); - - /* Notify that IO is complete */ - ntfy_notify(pchnl->ntfy_obj, DSP_STREAMIOCOMPLETION); -func_end: - return; -} - -/* - * ======== output_chnl ======== - * Purpose: - * Dispatch a buffer on an output channel. - */ -static void output_chnl(struct io_mgr *pio_mgr, struct chnl_object *pchnl, - u8 io_mode) -{ - struct chnl_mgr *chnl_mgr_obj; - struct shm *sm; - u32 chnl_id; - struct chnl_irp *chnl_packet_obj; - u32 dw_dsp_f_mask; - - chnl_mgr_obj = pio_mgr->chnl_mgr; - sm = pio_mgr->shared_mem; - /* Attempt to perform output */ - if (sm->output_full) - goto func_end; - - if (pchnl && !((pchnl->state & ~CHNL_STATEEOS) == CHNL_STATEREADY)) - goto func_end; - - /* Look to see if both a PC and DSP output channel are ready */ - dw_dsp_f_mask = sm->dsp_free_mask; - chnl_id = - find_ready_output(chnl_mgr_obj, pchnl, - (chnl_mgr_obj->output_mask & dw_dsp_f_mask)); - if (chnl_id == OUTPUTNOTREADY) - goto func_end; - - pchnl = chnl_mgr_obj->channels[chnl_id]; - if (!pchnl || list_empty(&pchnl->io_requests)) { - /* Shouldn't get here */ - goto func_end; - } - - if (!pchnl->cio_reqs) - goto func_end; - - /* Get the I/O request, and attempt a transfer */ - chnl_packet_obj = list_first_entry(&pchnl->io_requests, - struct chnl_irp, link); - list_del(&chnl_packet_obj->link); - - pchnl->cio_reqs--; - - /* Record fact that no more I/O buffers available */ - if (list_empty(&pchnl->io_requests)) - chnl_mgr_obj->output_mask &= ~(1 << chnl_id); - - /* Transfer buffer to DSP side */ - chnl_packet_obj->byte_size = min(pio_mgr->sm_buf_size, - chnl_packet_obj->byte_size); - memcpy(pio_mgr->output, chnl_packet_obj->host_sys_buf, - chnl_packet_obj->byte_size); - pchnl->bytes_moved += chnl_packet_obj->byte_size; - /* Write all 32 bits of arg */ - sm->arg = chnl_packet_obj->arg; -#if _CHNL_WORDSIZE == 2 - /* Access can be different SM access word size (e.g. 16/32 bit words) */ - sm->output_id = (u16) chnl_id; - sm->output_size = (u16) (chnl_packet_obj->byte_size + - chnl_mgr_obj->word_size - 1) / - (u16) chnl_mgr_obj->word_size; -#else - sm->output_id = chnl_id; - sm->output_size = (chnl_packet_obj->byte_size + - chnl_mgr_obj->word_size - 1) / chnl_mgr_obj->word_size; -#endif - sm->output_full = 1; - /* Indicate to the DSP we have written the output */ - sm_interrupt_dsp(pio_mgr->bridge_context, MBX_PCPY_CLASS); - /* Notify client with IO completion record (keep EOS) */ - chnl_packet_obj->status &= CHNL_IOCSTATEOS; - notify_chnl_complete(pchnl, chnl_packet_obj); - /* Notify if stream is done. */ - if (chnl_packet_obj->status & CHNL_IOCSTATEOS) - ntfy_notify(pchnl->ntfy_obj, DSP_STREAMDONE); - -func_end: - return; -} - -/* - * ======== output_msg ======== - * Copies messages from the message queues to the shared memory. - */ -static void output_msg(struct io_mgr *pio_mgr, struct msg_mgr *hmsg_mgr) -{ - u32 num_msgs = 0; - u32 i; - struct msg_dspmsg *msg_output; - struct msg_frame *pmsg; - struct msg_ctrl *msg_ctr_obj; - u32 val; - u32 addr; - - msg_ctr_obj = pio_mgr->msg_output_ctrl; - - /* Check if output has been cleared */ - if (!msg_ctr_obj->buf_empty) - return; - - num_msgs = (hmsg_mgr->msgs_pending > hmsg_mgr->max_msgs) ? - hmsg_mgr->max_msgs : hmsg_mgr->msgs_pending; - msg_output = (struct msg_dspmsg *) pio_mgr->msg_output; - - /* Copy num_msgs messages into shared memory */ - for (i = 0; i < num_msgs; i++) { - if (list_empty(&hmsg_mgr->msg_used_list)) - continue; - - pmsg = list_first_entry(&hmsg_mgr->msg_used_list, - struct msg_frame, list_elem); - list_del(&pmsg->list_elem); - - val = (pmsg->msg_data).msgq_id; - addr = (u32) &msg_output->msgq_id; - write_ext32_bit_dsp_data(pio_mgr->bridge_context, addr, val); - - val = (pmsg->msg_data).msg.cmd; - addr = (u32) &msg_output->msg.cmd; - write_ext32_bit_dsp_data(pio_mgr->bridge_context, addr, val); - - val = (pmsg->msg_data).msg.arg1; - addr = (u32) &msg_output->msg.arg1; - write_ext32_bit_dsp_data(pio_mgr->bridge_context, addr, val); - - val = (pmsg->msg_data).msg.arg2; - addr = (u32) &msg_output->msg.arg2; - write_ext32_bit_dsp_data(pio_mgr->bridge_context, addr, val); - - msg_output++; - list_add_tail(&pmsg->list_elem, &hmsg_mgr->msg_free_list); - sync_set_event(hmsg_mgr->sync_event); - } - - if (num_msgs > 0) { - hmsg_mgr->msgs_pending -= num_msgs; -#if _CHNL_WORDSIZE == 2 - /* - * Access can be different SM access word size - * (e.g. 16/32 bit words) - */ - msg_ctr_obj->size = (u16) num_msgs; -#else - msg_ctr_obj->size = num_msgs; -#endif - msg_ctr_obj->buf_empty = false; - /* Set the post SWI flag */ - msg_ctr_obj->post_swi = true; - /* Tell the DSP we have written the output. */ - sm_interrupt_dsp(pio_mgr->bridge_context, MBX_PCPY_CLASS); - } -} - -/* - * ======== register_shm_segs ======== - * purpose: - * Registers GPP SM segment with CMM. - */ -static int register_shm_segs(struct io_mgr *hio_mgr, - struct cod_manager *cod_man, - u32 dw_gpp_base_pa) -{ - int status = 0; - u32 ul_shm0_base = 0; - u32 shm0_end = 0; - u32 ul_shm0_rsrvd_start = 0; - u32 ul_rsrvd_size = 0; - u32 ul_gpp_phys; - u32 ul_dsp_virt; - u32 ul_shm_seg_id0 = 0; - u32 dw_offset, dw_gpp_base_va, ul_dsp_size; - - /* - * Read address and size info for first SM region. - * Get start of 1st SM Heap region. - */ - status = - cod_get_sym_value(cod_man, SHM0_SHARED_BASE_SYM, &ul_shm0_base); - if (ul_shm0_base == 0) { - status = -EPERM; - goto func_end; - } - /* Get end of 1st SM Heap region */ - if (!status) { - /* Get start and length of message part of shared memory */ - status = cod_get_sym_value(cod_man, SHM0_SHARED_END_SYM, - &shm0_end); - if (shm0_end == 0) { - status = -EPERM; - goto func_end; - } - } - /* Start of Gpp reserved region */ - if (!status) { - /* Get start and length of message part of shared memory */ - status = - cod_get_sym_value(cod_man, SHM0_SHARED_RESERVED_BASE_SYM, - &ul_shm0_rsrvd_start); - if (ul_shm0_rsrvd_start == 0) { - status = -EPERM; - goto func_end; - } - } - /* Register with CMM */ - if (!status) { - status = dev_get_cmm_mgr(hio_mgr->dev_obj, &hio_mgr->cmm_mgr); - if (!status) { - status = cmm_un_register_gppsm_seg(hio_mgr->cmm_mgr, - CMM_ALLSEGMENTS); - } - } - /* Register new SM region(s) */ - if (!status && (shm0_end - ul_shm0_base) > 0) { - /* Calc size (bytes) of SM the GPP can alloc from */ - ul_rsrvd_size = - (shm0_end - ul_shm0_rsrvd_start + 1) * hio_mgr->word_size; - if (ul_rsrvd_size <= 0) { - status = -EPERM; - goto func_end; - } - /* Calc size of SM DSP can alloc from */ - ul_dsp_size = - (ul_shm0_rsrvd_start - ul_shm0_base) * hio_mgr->word_size; - if (ul_dsp_size <= 0) { - status = -EPERM; - goto func_end; - } - /* First TLB entry reserved for Bridge SM use. */ - ul_gpp_phys = hio_mgr->ext_proc_info.ty_tlb[0].gpp_phys; - /* Get size in bytes */ - ul_dsp_virt = - hio_mgr->ext_proc_info.ty_tlb[0].dsp_virt * - hio_mgr->word_size; - /* - * Calc byte offset used to convert GPP phys <-> DSP byte - * address. - */ - if (dw_gpp_base_pa > ul_dsp_virt) - dw_offset = dw_gpp_base_pa - ul_dsp_virt; - else - dw_offset = ul_dsp_virt - dw_gpp_base_pa; - - if (ul_shm0_rsrvd_start * hio_mgr->word_size < ul_dsp_virt) { - status = -EPERM; - goto func_end; - } - /* - * Calc Gpp phys base of SM region. - * This is actually uncached kernel virtual address. - */ - dw_gpp_base_va = - ul_gpp_phys + ul_shm0_rsrvd_start * hio_mgr->word_size - - ul_dsp_virt; - /* - * Calc Gpp phys base of SM region. - * This is the physical address. - */ - dw_gpp_base_pa = - dw_gpp_base_pa + ul_shm0_rsrvd_start * hio_mgr->word_size - - ul_dsp_virt; - /* Register SM Segment 0. */ - status = - cmm_register_gppsm_seg(hio_mgr->cmm_mgr, dw_gpp_base_pa, - ul_rsrvd_size, dw_offset, - (dw_gpp_base_pa > - ul_dsp_virt) ? CMM_ADDTODSPPA : - CMM_SUBFROMDSPPA, - (u32) (ul_shm0_base * - hio_mgr->word_size), - ul_dsp_size, &ul_shm_seg_id0, - dw_gpp_base_va); - /* First SM region is seg_id = 1 */ - if (ul_shm_seg_id0 != 1) - status = -EPERM; - } -func_end: - return status; -} - -/* ZCPY IO routines. */ -/* - * ======== IO_SHMcontrol ======== - * Sets the requested shm setting. - */ -int io_sh_msetting(struct io_mgr *hio_mgr, u8 desc, void *pargs) -{ -#ifdef CONFIG_TIDSPBRIDGE_DVFS - u32 i; - struct dspbridge_platform_data *pdata = - omap_dspbridge_dev->dev.platform_data; - - switch (desc) { - case SHM_CURROPP: - /* Update the shared memory with requested OPP information */ - if (pargs != NULL) - hio_mgr->shared_mem->opp_table_struct.curr_opp_pt = - *(u32 *) pargs; - else - return -EPERM; - break; - case SHM_OPPINFO: - /* - * Update the shared memory with the voltage, frequency, - * min and max frequency values for an OPP. - */ - for (i = 0; i <= dsp_max_opps; i++) { - hio_mgr->shared_mem->opp_table_struct.opp_point[i]. - voltage = vdd1_dsp_freq[i][0]; - dev_dbg(bridge, "OPP-shm: voltage: %d\n", - vdd1_dsp_freq[i][0]); - hio_mgr->shared_mem->opp_table_struct. - opp_point[i].frequency = vdd1_dsp_freq[i][1]; - dev_dbg(bridge, "OPP-shm: frequency: %d\n", - vdd1_dsp_freq[i][1]); - hio_mgr->shared_mem->opp_table_struct.opp_point[i]. - min_freq = vdd1_dsp_freq[i][2]; - dev_dbg(bridge, "OPP-shm: min freq: %d\n", - vdd1_dsp_freq[i][2]); - hio_mgr->shared_mem->opp_table_struct.opp_point[i]. - max_freq = vdd1_dsp_freq[i][3]; - dev_dbg(bridge, "OPP-shm: max freq: %d\n", - vdd1_dsp_freq[i][3]); - } - hio_mgr->shared_mem->opp_table_struct.num_opp_pts = - dsp_max_opps; - dev_dbg(bridge, "OPP-shm: max OPP number: %d\n", dsp_max_opps); - /* Update the current OPP number */ - if (pdata->dsp_get_opp) - i = (*pdata->dsp_get_opp) (); - hio_mgr->shared_mem->opp_table_struct.curr_opp_pt = i; - dev_dbg(bridge, "OPP-shm: value programmed = %d\n", i); - break; - case SHM_GETOPP: - /* Get the OPP that DSP has requested */ - *(u32 *) pargs = hio_mgr->shared_mem->opp_request.rqst_opp_pt; - break; - default: - break; - } -#endif - return 0; -} - -/* - * ======== bridge_io_get_proc_load ======== - * Gets the Processor's Load information - */ -int bridge_io_get_proc_load(struct io_mgr *hio_mgr, - struct dsp_procloadstat *proc_lstat) -{ - if (!hio_mgr->shared_mem) - return -EFAULT; - - proc_lstat->curr_load = - hio_mgr->shared_mem->load_mon_info.curr_dsp_load; - proc_lstat->predicted_load = - hio_mgr->shared_mem->load_mon_info.pred_dsp_load; - proc_lstat->curr_dsp_freq = - hio_mgr->shared_mem->load_mon_info.curr_dsp_freq; - proc_lstat->predicted_freq = - hio_mgr->shared_mem->load_mon_info.pred_dsp_freq; - - dev_dbg(bridge, "Curr Load = %d, Pred Load = %d, Curr Freq = %d, " - "Pred Freq = %d\n", proc_lstat->curr_load, - proc_lstat->predicted_load, proc_lstat->curr_dsp_freq, - proc_lstat->predicted_freq); - return 0; -} - - -#if defined(CONFIG_TIDSPBRIDGE_BACKTRACE) -void print_dsp_debug_trace(struct io_mgr *hio_mgr) -{ - u32 ul_new_message_length = 0, ul_gpp_cur_pointer; - - while (true) { - /* Get the DSP current pointer */ - ul_gpp_cur_pointer = - *(u32 *) (hio_mgr->trace_buffer_current); - ul_gpp_cur_pointer = - hio_mgr->gpp_va + (ul_gpp_cur_pointer - - hio_mgr->dsp_va); - - /* No new debug messages available yet */ - if (ul_gpp_cur_pointer == hio_mgr->gpp_read_pointer) { - break; - } else if (ul_gpp_cur_pointer > hio_mgr->gpp_read_pointer) { - /* Continuous data */ - ul_new_message_length = - ul_gpp_cur_pointer - hio_mgr->gpp_read_pointer; - - memcpy(hio_mgr->msg, - (char *)hio_mgr->gpp_read_pointer, - ul_new_message_length); - hio_mgr->msg[ul_new_message_length] = '\0'; - /* - * Advance the GPP trace pointer to DSP current - * pointer. - */ - hio_mgr->gpp_read_pointer += ul_new_message_length; - /* Print the trace messages */ - pr_info("DSPTrace: %s\n", hio_mgr->msg); - } else if (ul_gpp_cur_pointer < hio_mgr->gpp_read_pointer) { - /* Handle trace buffer wraparound */ - memcpy(hio_mgr->msg, - (char *)hio_mgr->gpp_read_pointer, - hio_mgr->trace_buffer_end - - hio_mgr->gpp_read_pointer); - ul_new_message_length = - ul_gpp_cur_pointer - hio_mgr->trace_buffer_begin; - memcpy(&hio_mgr->msg[hio_mgr->trace_buffer_end - - hio_mgr->gpp_read_pointer], - (char *)hio_mgr->trace_buffer_begin, - ul_new_message_length); - hio_mgr->msg[hio_mgr->trace_buffer_end - - hio_mgr->gpp_read_pointer + - ul_new_message_length] = '\0'; - /* - * Advance the GPP trace pointer to DSP current - * pointer. - */ - hio_mgr->gpp_read_pointer = - hio_mgr->trace_buffer_begin + - ul_new_message_length; - /* Print the trace messages */ - pr_info("DSPTrace: %s\n", hio_mgr->msg); - } - } -} -#endif - -#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE -/* - * ======== print_dsp_trace_buffer ======== - * Prints the trace buffer returned from the DSP (if DBG_Trace is enabled). - * Parameters: - * hdeh_mgr: Handle to DEH manager object - * number of extra carriage returns to generate. - * Returns: - * 0: Success. - * -ENOMEM: Unable to allocate memory. - * Requires: - * hdeh_mgr muse be valid. Checked in bridge_deh_notify. - */ -int print_dsp_trace_buffer(struct bridge_dev_context *hbridge_context) -{ - int status = 0; - struct cod_manager *cod_mgr; - u32 ul_trace_end; - u32 ul_trace_begin; - u32 trace_cur_pos; - u32 ul_num_bytes = 0; - u32 ul_num_words = 0; - u32 ul_word_size = 2; - char *psz_buf; - char *str_beg; - char *trace_end; - char *buf_end; - char *new_line; - - struct bridge_dev_context *pbridge_context = hbridge_context; - struct bridge_drv_interface *intf_fxns; - struct dev_object *dev_obj = (struct dev_object *) - pbridge_context->dev_obj; - - status = dev_get_cod_mgr(dev_obj, &cod_mgr); - - if (cod_mgr) { - /* Look for SYS_PUTCBEG/SYS_PUTCEND */ - status = - cod_get_sym_value(cod_mgr, COD_TRACEBEG, &ul_trace_begin); - } else { - status = -EFAULT; - } - if (!status) - status = - cod_get_sym_value(cod_mgr, COD_TRACEEND, &ul_trace_end); - - if (!status) - /* trace_cur_pos will hold the address of a DSP pointer */ - status = cod_get_sym_value(cod_mgr, COD_TRACECURPOS, - &trace_cur_pos); - - if (status) - goto func_end; - - ul_num_bytes = (ul_trace_end - ul_trace_begin); - - ul_num_words = ul_num_bytes * ul_word_size; - status = dev_get_intf_fxns(dev_obj, &intf_fxns); - - if (status) - goto func_end; - - psz_buf = kzalloc(ul_num_bytes + 2, GFP_ATOMIC); - if (psz_buf != NULL) { - /* Read trace buffer data */ - status = (*intf_fxns->brd_read)(pbridge_context, - (u8 *)psz_buf, (u32)ul_trace_begin, - ul_num_bytes, 0); - - if (status) - goto func_end; - - /* Pack and do newline conversion */ - pr_debug("PrintDspTraceBuffer: " - "before pack and unpack.\n"); - pr_debug("%s: DSP Trace Buffer Begin:\n" - "=======================\n%s\n", - __func__, psz_buf); - - /* Read the value at the DSP address in trace_cur_pos. */ - status = (*intf_fxns->brd_read)(pbridge_context, - (u8 *)&trace_cur_pos, (u32)trace_cur_pos, - 4, 0); - if (status) - goto func_end; - /* Pack and do newline conversion */ - pr_info("DSP Trace Buffer Begin:\n" - "=======================\n%s\n", - psz_buf); - - - /* convert to offset */ - trace_cur_pos = trace_cur_pos - ul_trace_begin; - - if (ul_num_bytes) { - /* - * The buffer is not full, find the end of the - * data -- buf_end will be >= pszBuf after - * while. - */ - buf_end = &psz_buf[ul_num_bytes+1]; - /* DSP print position */ - trace_end = &psz_buf[trace_cur_pos]; - - /* - * Search buffer for a new_line and replace it - * with '\0', then print as string. - * Continue until end of buffer is reached. - */ - str_beg = trace_end; - ul_num_bytes = buf_end - str_beg; - - while (str_beg < buf_end) { - new_line = strnchr(str_beg, ul_num_bytes, - '\n'); - if (new_line && new_line < buf_end) { - *new_line = 0; - pr_debug("%s\n", str_beg); - str_beg = ++new_line; - ul_num_bytes = buf_end - str_beg; - } else { - /* - * Assume buffer empty if it contains - * a zero - */ - if (*str_beg != '\0') { - str_beg[ul_num_bytes] = 0; - pr_debug("%s\n", str_beg); - } - str_beg = buf_end; - ul_num_bytes = 0; - } - } - /* - * Search buffer for a nNewLine and replace it - * with '\0', then print as string. - * Continue until buffer is exhausted. - */ - str_beg = psz_buf; - ul_num_bytes = trace_end - str_beg; - - while (str_beg < trace_end) { - new_line = strnchr(str_beg, ul_num_bytes, '\n'); - if (new_line != NULL && new_line < trace_end) { - *new_line = 0; - pr_debug("%s\n", str_beg); - str_beg = ++new_line; - ul_num_bytes = trace_end - str_beg; - } else { - /* - * Assume buffer empty if it contains - * a zero - */ - if (*str_beg != '\0') { - str_beg[ul_num_bytes] = 0; - pr_debug("%s\n", str_beg); - } - str_beg = trace_end; - ul_num_bytes = 0; - } - } - } - pr_info("\n=======================\n" - "DSP Trace Buffer End:\n"); - kfree(psz_buf); - } else { - status = -ENOMEM; - } -func_end: - if (status) - dev_dbg(bridge, "%s Failed, status 0x%x\n", __func__, status); - return status; -} - -/** - * dump_dsp_stack() - This function dumps the data on the DSP stack. - * @bridge_context: Bridge driver's device context pointer. - * - */ -int dump_dsp_stack(struct bridge_dev_context *bridge_context) -{ - int status = 0; - struct cod_manager *code_mgr; - struct node_mgr *node_mgr; - u32 trace_begin; - char name[256]; - struct { - u32 head[2]; - u32 size; - } mmu_fault_dbg_info; - u32 *buffer; - u32 *buffer_beg; - u32 *buffer_end; - u32 exc_type; - u32 dyn_ext_base; - u32 i; - u32 offset_output; - u32 total_size; - u32 poll_cnt; - const char *dsp_regs[] = {"EFR", "IERR", "ITSR", "NTSR", - "IRP", "NRP", "AMR", "SSR", - "ILC", "RILC", "IER", "CSR"}; - const char *exec_ctxt[] = {"Task", "SWI", "HWI", "Unknown"}; - struct bridge_drv_interface *intf_fxns; - struct dev_object *dev_object = bridge_context->dev_obj; - - status = dev_get_cod_mgr(dev_object, &code_mgr); - if (!code_mgr) { - pr_debug("%s: Failed on dev_get_cod_mgr.\n", __func__); - status = -EFAULT; - } - - if (!status) { - status = dev_get_node_manager(dev_object, &node_mgr); - if (!node_mgr) { - pr_debug("%s: Failed on dev_get_node_manager.\n", - __func__); - status = -EFAULT; - } - } - - if (!status) { - /* Look for SYS_PUTCBEG/SYS_PUTCEND: */ - status = - cod_get_sym_value(code_mgr, COD_TRACEBEG, &trace_begin); - pr_debug("%s: trace_begin Value 0x%x\n", - __func__, trace_begin); - if (status) - pr_debug("%s: Failed on cod_get_sym_value.\n", - __func__); - } - if (!status) - status = dev_get_intf_fxns(dev_object, &intf_fxns); - /* - * Check for the "magic number" in the trace buffer. If it has - * yet to appear then poll the trace buffer to wait for it. Its - * appearance signals that the DSP has finished dumping its state. - */ - mmu_fault_dbg_info.head[0] = 0; - mmu_fault_dbg_info.head[1] = 0; - if (!status) { - poll_cnt = 0; - while ((mmu_fault_dbg_info.head[0] != MMU_FAULT_HEAD1 || - mmu_fault_dbg_info.head[1] != MMU_FAULT_HEAD2) && - poll_cnt < POLL_MAX) { - - /* Read DSP dump size from the DSP trace buffer... */ - status = (*intf_fxns->brd_read)(bridge_context, - (u8 *)&mmu_fault_dbg_info, (u32)trace_begin, - sizeof(mmu_fault_dbg_info), 0); - - if (status) - break; - - poll_cnt++; - } - - if (mmu_fault_dbg_info.head[0] != MMU_FAULT_HEAD1 && - mmu_fault_dbg_info.head[1] != MMU_FAULT_HEAD2) { - status = -ETIME; - pr_err("%s:No DSP MMU-Fault information available.\n", - __func__); - } - } - - if (!status) { - total_size = mmu_fault_dbg_info.size; - /* Limit the size in case DSP went crazy */ - if (total_size > MAX_MMU_DBGBUFF) - total_size = MAX_MMU_DBGBUFF; - - buffer = kzalloc(total_size, GFP_ATOMIC); - if (!buffer) { - status = -ENOMEM; - pr_debug("%s: Failed to " - "allocate stack dump buffer.\n", __func__); - goto func_end; - } - - buffer_beg = buffer; - buffer_end = buffer + total_size / 4; - - /* Read bytes from the DSP trace buffer... */ - status = (*intf_fxns->brd_read)(bridge_context, - (u8 *)buffer, (u32)trace_begin, - total_size, 0); - if (status) { - pr_debug("%s: Failed to Read Trace Buffer.\n", - __func__); - goto func_end; - } - - pr_err("\nAproximate Crash Position:\n" - "--------------------------\n"); - - exc_type = buffer[3]; - if (!exc_type) - i = buffer[79]; /* IRP */ - else - i = buffer[80]; /* NRP */ - - status = - cod_get_sym_value(code_mgr, DYNEXTBASE, &dyn_ext_base); - if (status) { - status = -EFAULT; - goto func_end; - } - - if ((i > dyn_ext_base) && (node_find_addr(node_mgr, i, - 0x1000, &offset_output, name) == 0)) - pr_err("0x%-8x [\"%s\" + 0x%x]\n", i, name, - i - offset_output); - else - pr_err("0x%-8x [Unable to match to a symbol.]\n", i); - - buffer += 4; - - pr_err("\nExecution Info:\n" - "---------------\n"); - - if (*buffer < ARRAY_SIZE(exec_ctxt)) { - pr_err("Execution context \t%s\n", - exec_ctxt[*buffer++]); - } else { - pr_err("Execution context corrupt\n"); - kfree(buffer_beg); - return -EFAULT; - } - pr_err("Task Handle\t\t0x%x\n", *buffer++); - pr_err("Stack Pointer\t\t0x%x\n", *buffer++); - pr_err("Stack Top\t\t0x%x\n", *buffer++); - pr_err("Stack Bottom\t\t0x%x\n", *buffer++); - pr_err("Stack Size\t\t0x%x\n", *buffer++); - pr_err("Stack Size In Use\t0x%x\n", *buffer++); - - pr_err("\nCPU Registers\n" - "---------------\n"); - - for (i = 0; i < 32; i++) { - if (i == 4 || i == 6 || i == 8) - pr_err("A%d 0x%-8x [Function Argument %d]\n", - i, *buffer++, i-3); - else if (i == 15) - pr_err("A15 0x%-8x [Frame Pointer]\n", - *buffer++); - else - pr_err("A%d 0x%x\n", i, *buffer++); - } - - pr_err("\nB0 0x%x\n", *buffer++); - pr_err("B1 0x%x\n", *buffer++); - pr_err("B2 0x%x\n", *buffer++); - - if ((*buffer > dyn_ext_base) && (node_find_addr(node_mgr, - *buffer, 0x1000, &offset_output, name) == 0)) - - pr_err("B3 0x%-8x [Function Return Pointer:" - " \"%s\" + 0x%x]\n", *buffer, name, - *buffer - offset_output); - else - pr_err("B3 0x%-8x [Function Return Pointer:" - "Unable to match to a symbol.]\n", *buffer); - - buffer++; - - for (i = 4; i < 32; i++) { - if (i == 4 || i == 6 || i == 8) - pr_err("B%d 0x%-8x [Function Argument %d]\n", - i, *buffer++, i-2); - else if (i == 14) - pr_err("B14 0x%-8x [Data Page Pointer]\n", - *buffer++); - else - pr_err("B%d 0x%x\n", i, *buffer++); - } - - pr_err("\n"); - - for (i = 0; i < ARRAY_SIZE(dsp_regs); i++) - pr_err("%s 0x%x\n", dsp_regs[i], *buffer++); - - pr_err("\nStack:\n" - "------\n"); - - for (i = 0; buffer < buffer_end; i++, buffer++) { - if ((*buffer > dyn_ext_base) && ( - node_find_addr(node_mgr, *buffer , 0x600, - &offset_output, name) == 0)) - pr_err("[%d] 0x%-8x [\"%s\" + 0x%x]\n", - i, *buffer, name, - *buffer - offset_output); - else - pr_err("[%d] 0x%x\n", i, *buffer); - } - kfree(buffer_beg); - } -func_end: - return status; -} - -/** - * dump_dl_modules() - This functions dumps the _DLModules loaded in DSP side - * @bridge_context: Bridge driver's device context pointer. - * - */ -void dump_dl_modules(struct bridge_dev_context *bridge_context) -{ - struct cod_manager *code_mgr; - struct bridge_drv_interface *intf_fxns; - struct bridge_dev_context *bridge_ctxt = bridge_context; - struct dev_object *dev_object = bridge_ctxt->dev_obj; - struct modules_header modules_hdr; - struct dll_module *module_struct = NULL; - u32 module_dsp_addr; - u32 module_size; - u32 module_struct_size = 0; - u32 sect_ndx; - char *sect_str; - int status = 0; - - status = dev_get_intf_fxns(dev_object, &intf_fxns); - if (status) { - pr_debug("%s: Failed on dev_get_intf_fxns.\n", __func__); - goto func_end; - } - - status = dev_get_cod_mgr(dev_object, &code_mgr); - if (!code_mgr) { - pr_debug("%s: Failed on dev_get_cod_mgr.\n", __func__); - status = -EFAULT; - goto func_end; - } - - /* Lookup the address of the modules_header structure */ - status = cod_get_sym_value(code_mgr, "_DLModules", &module_dsp_addr); - if (status) { - pr_debug("%s: Failed on cod_get_sym_value for _DLModules.\n", - __func__); - goto func_end; - } - - pr_debug("%s: _DLModules at 0x%x\n", __func__, module_dsp_addr); - - /* Copy the modules_header structure from DSP memory. */ - status = (*intf_fxns->brd_read)(bridge_context, (u8 *) &modules_hdr, - (u32) module_dsp_addr, sizeof(modules_hdr), 0); - - if (status) { - pr_debug("%s: Failed failed to read modules header.\n", - __func__); - goto func_end; - } - - module_dsp_addr = modules_hdr.first_module; - module_size = modules_hdr.first_module_size; - - pr_debug("%s: dll_module_header 0x%x %d\n", __func__, module_dsp_addr, - module_size); - - pr_err("\nDynamically Loaded Modules:\n" - "---------------------------\n"); - - /* For each dll_module structure in the list... */ - while (module_size) { - /* - * Allocate/re-allocate memory to hold the dll_module - * structure. The memory is re-allocated only if the existing - * allocation is too small. - */ - if (module_size > module_struct_size) { - kfree(module_struct); - module_struct = kzalloc(module_size+128, GFP_ATOMIC); - module_struct_size = module_size+128; - pr_debug("%s: allocated module struct %p %d\n", - __func__, module_struct, module_struct_size); - if (!module_struct) - goto func_end; - } - /* Copy the dll_module structure from DSP memory */ - status = (*intf_fxns->brd_read)(bridge_context, - (u8 *)module_struct, module_dsp_addr, module_size, 0); - - if (status) { - pr_debug( - "%s: Failed to read dll_module struct for 0x%x.\n", - __func__, module_dsp_addr); - break; - } - - /* Update info regarding the _next_ module in the list. */ - module_dsp_addr = module_struct->next_module; - module_size = module_struct->next_module_size; - - pr_debug("%s: next module 0x%x %d, this module num sects %d\n", - __func__, module_dsp_addr, module_size, - module_struct->num_sects); - - /* - * The section name strings start immediately following - * the array of dll_sect structures. - */ - sect_str = (char *) &module_struct-> - sects[module_struct->num_sects]; - pr_err("%s\n", sect_str); - - /* - * Advance to the first section name string. - * Each string follows the one before. - */ - sect_str += strlen(sect_str) + 1; - - /* Access each dll_sect structure and its name string. */ - for (sect_ndx = 0; - sect_ndx < module_struct->num_sects; sect_ndx++) { - pr_err(" Section: 0x%x ", - module_struct->sects[sect_ndx].sect_load_adr); - - if (((u32) sect_str - (u32) module_struct) < - module_struct_size) { - pr_err("%s\n", sect_str); - /* Each string follows the one before. */ - sect_str += strlen(sect_str)+1; - } else { - pr_err("<string error>\n"); - pr_debug("%s: section name sting address " - "is invalid %p\n", __func__, sect_str); - } - } - } -func_end: - kfree(module_struct); -} -#endif |