diff options
Diffstat (limited to 'cfe/cfe/main/cfe_iocb_dispatch.c')
-rwxr-xr-x | cfe/cfe/main/cfe_iocb_dispatch.c | 647 |
1 files changed, 647 insertions, 0 deletions
diff --git a/cfe/cfe/main/cfe_iocb_dispatch.c b/cfe/cfe/main/cfe_iocb_dispatch.c new file mode 100755 index 0000000..24aea0a --- /dev/null +++ b/cfe/cfe/main/cfe_iocb_dispatch.c @@ -0,0 +1,647 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * IOCB dispatcher File: cfe_iocb_dispatch.c + * + * This routine is the main API dispatch for CFE. User API + * calls, via the ROM entry point, get dispatched to routines + * in this module. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_malloc.h" +#include "lib_queue.h" +#include "lib_printf.h" +#include "lib_string.h" +#include "cfe_iocb.h" +#include "cfe_error.h" +#include "cfe_device.h" +#include "cfe_timer.h" +#include "cfe_mem.h" +#include "cfe_fileops.h" +#include "cfe_boot.h" +#include "env_subr.h" +#include "cfe.h" +#include "cfe_console.h" +#include "bsp_config.h" +#include "initdata.h" + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#define HV 1 /* handle valid */ + +#ifndef CFG_BOARD_ID +#define CFG_BOARD_ID 0 +#endif + +/* ********************************************************************* + * Globals + ********************************************************************* */ + +cfe_devctx_t *cfe_handle_table[CFE_MAX_HANDLE]; + +extern void _cfe_flushcache(int); + +/* ********************************************************************* + * Prototypes + ********************************************************************* */ + +int cfe_iocb_dispatch(cfe_iocb_t *iocb); +void cfe_device_poll(void *); + +#if CFG_MULTI_CPUS +extern int altcpu_cmd_start(uint64_t,uint64_t *); +extern int altcpu_cmd_stop(uint64_t); +#endif + +/* ********************************************************************* + * Dispatch table + ********************************************************************* */ + +struct cfe_cmd_dispatch_s { + int plistsize; + int flags; + int (*func)(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +}; + + +static int cfe_cmd_fw_getinfo(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_fw_restart(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_fw_boot(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_fw_cpuctl(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_fw_gettime(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_fw_memenum(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_fw_flushcache(cfe_devctx_t *ctx,cfe_iocb_t *iocb); + +static int cfe_cmd_dev_gethandle(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_dev_enum(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_dev_open(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_dev_inpstat(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_dev_read(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_dev_write(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_dev_ioctl(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_dev_close(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_dev_getinfo(cfe_devctx_t *ctx,cfe_iocb_t *iocb); + +static int cfe_cmd_env_enum(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_env_get(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_env_set(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_env_del(cfe_devctx_t *ctx,cfe_iocb_t *iocb); + +const static struct cfe_cmd_dispatch_s cfe_cmd_dispatch_table[CFE_CMD_MAX] = { + {sizeof(iocb_fwinfo_t), 0, cfe_cmd_fw_getinfo}, /* 0 : CFE_CMD_FW_GETINFO */ + {sizeof(iocb_exitstat_t),0, cfe_cmd_fw_restart}, /* 1 : CFE_CMD_FW_RESTART */ + {sizeof(iocb_buffer_t), 0, cfe_cmd_fw_boot}, /* 2 : CFE_CMD_FW_BOOT */ + {sizeof(iocb_cpuctl_t), 0, cfe_cmd_fw_cpuctl}, /* 3 : CFE_CMD_FW_CPUCTL */ + {sizeof(iocb_time_t), 0, cfe_cmd_fw_gettime}, /* 4 : CFE_CMD_FW_GETTIME */ + {sizeof(iocb_meminfo_t),0, cfe_cmd_fw_memenum}, /* 5 : CFE_CMD_FW_MEMENUM */ + {0, 0, cfe_cmd_fw_flushcache}, /* 6 : CFE_CMD_FW_FLUSHCACHE */ + {-1, 0, NULL}, /* 7 : */ + {-1, 0, NULL}, /* 8 : */ + {0, 0, cfe_cmd_dev_gethandle}, /* 9 : CFE_CMD_DEV_GETHANDLE */ + {sizeof(iocb_envbuf_t), 0, cfe_cmd_dev_enum}, /* 10 : CFE_CMD_DEV_ENUM */ + {sizeof(iocb_buffer_t), 0, cfe_cmd_dev_open}, /* 11 : CFE_CMD_DEV_OPEN */ + {sizeof(iocb_inpstat_t),HV, cfe_cmd_dev_inpstat}, /* 12 : CFE_CMD_DEV_INPSTAT */ + {sizeof(iocb_buffer_t), HV, cfe_cmd_dev_read}, /* 13 : CFE_CMD_DEV_READ */ + {sizeof(iocb_buffer_t), HV, cfe_cmd_dev_write}, /* 14 : CFE_CMD_DEV_WRITE */ + {sizeof(iocb_buffer_t), HV, cfe_cmd_dev_ioctl}, /* 15 : CFE_CMD_DEV_IOCTL */ + {0, HV, cfe_cmd_dev_close}, /* 16 : CFE_CMD_DEV_CLOSE */ + {sizeof(iocb_buffer_t), 0, cfe_cmd_dev_getinfo}, /* 17 : CFE_CMD_DEV_GETINFO */ + {-1, 0, NULL}, /* 18 : */ + {-1, 0, NULL}, /* 19 : */ + {sizeof(iocb_envbuf_t), 0, cfe_cmd_env_enum}, /* 20 : CFE_CMD_ENV_ENUM */ + {-1, 0, NULL}, /* 21 : */ + {sizeof(iocb_envbuf_t), 0, cfe_cmd_env_get}, /* 22 : CFE_CMD_ENV_GET */ + {sizeof(iocb_envbuf_t), 0, cfe_cmd_env_set}, /* 23 : CFE_CMD_ENV_SET */ + {sizeof(iocb_envbuf_t), 0, cfe_cmd_env_del}, /* 24 : CFE_CMD_ENV_DEL */ + {-1, 0, NULL}, /* 25 : */ + {-1, 0, NULL}, /* 26 : */ + {-1, 0, NULL}, /* 27 : */ + {-1, 0, NULL}, /* 28 : */ + {-1, 0, NULL}, /* 29 : */ + {-1, 0, NULL}, /* 30 : */ + {-1, 0, NULL} /* 31 : */ +}; + +/* ********************************************************************* + * IOCB dispatch routines + ********************************************************************* */ + +void cfe_device_poll(void *x) +{ + int idx; + cfe_devctx_t **ctx = cfe_handle_table; + + for (idx = 0; idx < CFE_MAX_HANDLE; idx++,ctx++) { + if ((*ctx) && ((*ctx)->dev_dev->dev_dispatch->dev_poll)) { + (*ctx)->dev_dev->dev_dispatch->dev_poll(*ctx,cfe_ticks); + } + } +} + +int cfe_iocb_dispatch(cfe_iocb_t *iocb) +{ + const struct cfe_cmd_dispatch_s *disp; + int res; + cfe_devctx_t *ctx; + + /* + * Check for commands codes out of range + */ + + if ((iocb->iocb_fcode < 0) || (iocb->iocb_fcode >= CFE_CMD_MAX)) { + iocb->iocb_status = CFE_ERR_INV_COMMAND; + return iocb->iocb_status; + } + + /* + * Check for command codes in range but invalid + */ + + disp = &cfe_cmd_dispatch_table[iocb->iocb_fcode]; + + if (disp->plistsize < 0) { + iocb->iocb_status = CFE_ERR_INV_COMMAND; + return iocb->iocb_status; + } + + /* + * Check for invalid parameter list size + */ + + if (disp->plistsize != iocb->iocb_psize) { + iocb->iocb_status = CFE_ERR_INV_PARAM; + return iocb->iocb_status; + } + + /* + * Determine handle + */ + + ctx = NULL; + if (disp->flags & HV) { + if ((iocb->iocb_handle >= CFE_MAX_HANDLE) || + (iocb->iocb_handle < 0) || + (cfe_handle_table[iocb->iocb_handle] == NULL)){ + iocb->iocb_status = CFE_ERR_INV_PARAM; + return iocb->iocb_status; + } + ctx = cfe_handle_table[iocb->iocb_handle]; + } + + /* + * Dispatch to handler routine + */ + + res = (*disp->func)(ctx,iocb); + + iocb->iocb_status = res; + return res; +} + +static int cfe_newhandle(void) +{ + int idx; + + for (idx = 0; idx < CFE_MAX_HANDLE; idx++) { + if (cfe_handle_table[idx] == NULL) break; + } + + if (idx == CFE_MAX_HANDLE) return -1; + + return idx; +} + + +/* ********************************************************************* + * Implementation routines for each IOCB function + ********************************************************************* */ + +static int cfe_cmd_fw_getinfo(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + iocb_fwinfo_t *info = &iocb->plist.iocb_fwinfo; + + info->fwi_version = (CFE_VER_MAJOR << 16) | + (CFE_VER_MINOR << 8) | + (CFE_VER_BUILD); + info->fwi_totalmem = ((cfe_int64_t) mem_totalsize) << 20; + info->fwi_flags = +#ifdef __long64 + CFE_FWI_64BIT | +#else + CFE_FWI_32BIT | +#endif +#if (CFG_EMBEDDED_PIC) + CFE_FWI_RELOC | +#endif +#if (!CFG_RUNFROMKSEG0) + CFE_FWI_UNCACHED | +#endif +#if CFG_MULTI_CPUS + CFE_FWI_MULTICPU | +#endif +#ifdef _VERILOG_ + CFE_FWI_RTLSIM | +#endif +#ifdef _FUNCSIM_ + CFE_FWI_FUNCSIM | +#endif + 0; + + info->fwi_boardid = CFG_BOARD_ID; + info->fwi_bootarea_pa = (cfe_int64_t) mem_bootarea_start; + info->fwi_bootarea_va = BOOT_START_ADDRESS; + info->fwi_bootarea_size = (cfe_int64_t) mem_bootarea_size; + info->fwi_reserved1 = 0; + info->fwi_reserved2 = 0; + info->fwi_reserved3 = 0; + + return CFE_OK; +} + +static int cfe_cmd_fw_restart(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + if (iocb->iocb_flags & CFE_FLG_WARMSTART) { + cfe_warmstart(iocb->plist.iocb_exitstat.status); + } + else { + cfe_restart(); + } + + /* should not get here */ + + return CFE_OK; +} + +static int cfe_cmd_fw_boot(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + return CFE_ERR_INV_COMMAND; /* not implemented yet */ +} + +static int cfe_cmd_fw_cpuctl(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ +#if CFG_MULTI_CPUS + int res; + uint64_t startargs[4]; + + switch (iocb->plist.iocb_cpuctl.cpu_command) { + case CFE_CPU_CMD_START: + + startargs[0] = iocb->plist.iocb_cpuctl.start_addr; + startargs[1] = iocb->plist.iocb_cpuctl.sp_val; + startargs[2] = iocb->plist.iocb_cpuctl.gp_val; + startargs[3] = iocb->plist.iocb_cpuctl.a1_val; + + res = altcpu_cmd_start(iocb->plist.iocb_cpuctl.cpu_number, + startargs); + break; + case CFE_CPU_CMD_STOP: + res = altcpu_cmd_stop(iocb->plist.iocb_cpuctl.cpu_number); + break; + default: + res = CFE_ERR_INV_PARAM; + } + + return res; +#else + return CFE_ERR_INV_COMMAND; +#endif +} + +static int cfe_cmd_fw_gettime(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + POLL(); + + iocb->plist.iocb_time.ticks = cfe_ticks; + + return CFE_OK; +} + +static int cfe_cmd_fw_memenum(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + int type; + int res; + uint64_t addr,size; + + res = cfe_arena_enum(iocb->plist.iocb_meminfo.mi_idx, + &type, + &addr, + &size, + (iocb->iocb_flags & CFE_FLG_FULL_ARENA) ? TRUE : FALSE); + + iocb->plist.iocb_meminfo.mi_addr = addr; + iocb->plist.iocb_meminfo.mi_size = size; + iocb->plist.iocb_meminfo.mi_type = type; + + if (res == 0) { + if (type == MEMTYPE_DRAM_AVAILABLE) { + iocb->plist.iocb_meminfo.mi_type = CFE_MI_AVAILABLE; + } + else { + iocb->plist.iocb_meminfo.mi_type = CFE_MI_RESERVED; + } + } + + return res; +} + +static int cfe_cmd_fw_flushcache(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + _cfe_flushcache(iocb->iocb_flags); + return CFE_OK; +} + +static int cfe_cmd_dev_enum(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + return CFE_ERR_INV_COMMAND; +} + +static int cfe_cmd_dev_gethandle(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + switch (iocb->iocb_flags) { + case CFE_STDHANDLE_CONSOLE: + if (console_handle == -1) return CFE_ERR_DEVNOTFOUND; + iocb->iocb_handle = console_handle; + return CFE_OK; + break; + default: + return CFE_ERR_INV_PARAM; + } +} + +static int cfe_cmd_dev_open(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + int h; + cfe_device_t *dev; + char devname[64]; + int res; + + /* + * Get device name + */ + + xstrncpy(devname,(char*)iocb->plist.iocb_buffer.buf_ptr,sizeof(devname)); + + /* + * Find device in device table + */ + + dev = cfe_finddev(devname); + if (!dev) return CFE_ERR_DEVNOTFOUND; + + /* + * Fail if someone else already has the device open + */ + + if (dev->dev_opencount > 0) return CFE_ERR_DEVOPEN; + + /* + * Generate a new handle + */ + + h = cfe_newhandle(); + if (h < 0) return CFE_ERR_NOMEM; + + /* + * Allocate a context + */ + + ctx = (cfe_devctx_t *) KMALLOC(sizeof(cfe_devctx_t),0); + if (ctx == NULL) return CFE_ERR_NOMEM; + + /* + * Fill in the context + */ + + ctx->dev_dev = dev; + ctx->dev_softc = dev->dev_softc; + ctx->dev_openinfo = NULL; + + /* + * Call driver's open func + */ + + res = dev->dev_dispatch->dev_open(ctx); + + if (res != 0) { + KFREE(ctx); + return res; + } + + /* + * Increment refcnt and save handle + */ + + dev->dev_opencount++; + cfe_handle_table[h] = ctx; + iocb->iocb_handle = h; + + /* + * Success! + */ + + return CFE_OK; +} + +static int cfe_cmd_dev_inpstat(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + int status; + + status = ctx->dev_dev->dev_dispatch->dev_inpstat(ctx,&(iocb->plist.iocb_inpstat)); + + return status; +} + +static int cfe_cmd_dev_read(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + int status; + + status = ctx->dev_dev->dev_dispatch->dev_read(ctx,&(iocb->plist.iocb_buffer)); + + return status; +} + +static int cfe_cmd_dev_write(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + int status; + + status = ctx->dev_dev->dev_dispatch->dev_write(ctx,&(iocb->plist.iocb_buffer)); + + return status; +} + +static int cfe_cmd_dev_ioctl(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + int status; + + status = ctx->dev_dev->dev_dispatch->dev_ioctl(ctx,&(iocb->plist.iocb_buffer)); + + return status; +} + +static int cfe_cmd_dev_close(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + /* + * Call device close function + */ + + ctx->dev_dev->dev_dispatch->dev_close(ctx); + + /* + * Decrement refcnt + */ + + ctx->dev_dev->dev_opencount--; + + /* + * Wipe out handle + */ + + cfe_handle_table[iocb->iocb_handle] = NULL; + + /* + * Release device context + */ + + KFREE(ctx); + + return CFE_OK; +} + +static int cfe_cmd_dev_getinfo(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + cfe_device_t *dev; + char devname[64]; + char *x; + + /* + * Get device name + */ + + xstrncpy(devname,(char*)iocb->plist.iocb_buffer.buf_ptr,sizeof(devname)); + + /* + * Find device in device table + */ + + if ((x = strchr(devname,':'))) *x = '\0'; + dev = cfe_finddev(devname); + if (!dev) return CFE_ERR_DEVNOTFOUND; + + /* + * Return device class + */ + + iocb->plist.iocb_buffer.buf_devflags = dev->dev_class; + + return CFE_OK; +} + +static int cfe_cmd_env_enum(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + int vallen,namelen,res; + + namelen = iocb->plist.iocb_envbuf.name_length; + vallen = iocb->plist.iocb_envbuf.val_length; + + res = env_enum(iocb->plist.iocb_envbuf.enum_idx, + (char*)iocb->plist.iocb_envbuf.name_ptr, + &namelen, + (char*)iocb->plist.iocb_envbuf.val_ptr, + &vallen); + + if (res < 0) return CFE_ERR_ENVNOTFOUND; + + return CFE_OK; +} + + +static int cfe_cmd_env_get(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + char *env; + + env = env_getenv((char*)iocb->plist.iocb_envbuf.name_ptr); + + if (env == NULL) return CFE_ERR_ENVNOTFOUND; + + xstrncpy((char*)iocb->plist.iocb_envbuf.val_ptr, + env, + iocb->plist.iocb_envbuf.val_length); + + return CFE_OK; +} + +static int cfe_cmd_env_set(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + int res; + int flg; + + + flg = (iocb->iocb_flags & CFE_FLG_ENV_PERMANENT) ? + ENV_FLG_NORMAL : ENV_FLG_BUILTIN; + + res = env_setenv((char*)iocb->plist.iocb_envbuf.name_ptr, + (char*)iocb->plist.iocb_envbuf.val_ptr, + flg); + + if (res == 0) { + if (iocb->iocb_flags & CFE_FLG_ENV_PERMANENT) res = env_save(); + } + + if (res < 0) return res; + + return CFE_OK; +} + +static int cfe_cmd_env_del(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + int res; + + res = env_delenv((char*)iocb->plist.iocb_envbuf.name_ptr); + + return res; +} + + + |