diff options
Diffstat (limited to 'drivers/dsp/bridge/wmd/ue_deh.c')
-rw-r--r-- | drivers/dsp/bridge/wmd/ue_deh.c | 385 |
1 files changed, 385 insertions, 0 deletions
diff --git a/drivers/dsp/bridge/wmd/ue_deh.c b/drivers/dsp/bridge/wmd/ue_deh.c new file mode 100644 index 000000000000..1034641c380d --- /dev/null +++ b/drivers/dsp/bridge/wmd/ue_deh.c @@ -0,0 +1,385 @@ +/* + * ue_deh.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * 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. + */ + + +/* + * ======== ue_deh.c ======== + * Description: + * Implements upper edge DSP exception handling (DEH) functions. + * + *! Revision History: + *! ================ + *! 03-Jan-2005 hn: Support for IVA DEH. + *! 05-Jan-2004 vp: Updated for the 24xx HW library. + *! 19-Feb-2003 vp: Code review updates. + *! - Cosmetic changes. + *! 18-Oct-2002 sb: Ported to Linux platform. + *! 10-Dec-2001 kc: Updated DSP error reporting in DEBUG mode. + *! 10-Sep-2001 kc: created. + */ + +/* ----------------------------------- Host OS */ +#include <dspbridge/host_os.h> + +/* ----------------------------------- DSP/BIOS Bridge */ +#include <dspbridge/std.h> +#include <dspbridge/dbdefs.h> +#include <dspbridge/errbase.h> + +/* ----------------------------------- Trace & Debug */ +#include <dspbridge/dbc.h> +#include <dspbridge/dbg.h> + +/* ----------------------------------- OS Adaptation Layer */ +#include <dspbridge/csl.h> +#include <dspbridge/cfg.h> +#include <dspbridge/dpc.h> +#include <dspbridge/mem.h> +#include <dspbridge/ntfy.h> +#include <dspbridge/drv.h> + +/* ----------------------------------- Link Driver */ +#include <dspbridge/wmddeh.h> + +/* ----------------------------------- Platform Manager */ +#include <dspbridge/dev.h> +#include <dspbridge/wcd.h> + +/* ------------------------------------ Hardware Abstraction Layer */ +#include <hw_defs.h> +#include <hw_mmu.h> + +/*--------------------------------------Notify*/ +#include <syslink/notify.h> +#include <syslink/notify_driverdefs.h> + + +/* ----------------------------------- This */ +#include "mmu_fault.h" +#include "_tiomap.h" +#include "_deh.h" +#include "_tiomap_mmu.h" +#include "_tiomap_pwr.h" +#include <dspbridge/io_sm.h> + +static struct HW_MMUMapAttrs_t mapAttrs = { HW_LITTLE_ENDIAN, + HW_ELEM_SIZE_16BIT, + HW_MMU_CPUES} ; +#define VirtToPhys(x) ((x) - PAGE_OFFSET + PHYS_OFFSET) + +static u32 dummyVaAddr; +/* + * ======== WMD_DEH_Create ======== + * Creates DEH manager object. + */ +DSP_STATUS WMD_DEH_Create(OUT struct DEH_MGR **phDehMgr, + struct DEV_OBJECT *hDevObject) +{ + DSP_STATUS status = DSP_SOK; + struct DEH_MGR *pDehMgr = NULL; + struct CFG_HOSTRES cfgHostRes; + struct CFG_DEVNODE *hDevNode; + struct WMD_DEV_CONTEXT *hWmdContext = NULL; + + DBG_Trace(DBG_LEVEL1, "Entering DEH_Create: 0x%x\n", phDehMgr); + /* Message manager will be created when a file is loaded, since + * size of message buffer in shared memory is configurable in + * the base image. */ + /* Get WMD context info. */ + DEV_GetWMDContext(hDevObject, &hWmdContext); + DBC_Assert(hWmdContext); + dummyVaAddr = 0; + /* Allocate IO manager object: */ + MEM_AllocObject(pDehMgr, struct DEH_MGR, SIGNATURE); + if (pDehMgr == NULL) { + status = DSP_EMEMORY; + } else { + /* Create an NTFY object to manage notifications */ + if (DSP_SUCCEEDED(status)) + status = NTFY_Create(&pDehMgr->hNtfy); + + /* Create a DPC object. */ + status = DPC_Create(&pDehMgr->hMmuFaultDpc, MMU_FaultDpc, + (void *)pDehMgr); + if (DSP_SUCCEEDED(status)) + status = DEV_GetDevNode(hDevObject, &hDevNode); + + if (DSP_SUCCEEDED(status)) + status = CFG_GetHostResources(hDevNode, &cfgHostRes); + + if (DSP_SUCCEEDED(status)) { + /* Fill in context structure */ + pDehMgr->hWmdContext = hWmdContext; + pDehMgr->errInfo.dwErrMask = 0L; + pDehMgr->errInfo.dwVal1 = 0L; + pDehMgr->errInfo.dwVal2 = 0L; + pDehMgr->errInfo.dwVal3 = 0L; + /* Install ISR function for DSP MMU fault */ + if ((request_irq(INT_DSP_MMU_IRQ, MMU_FaultIsr, 0, + "DspBridge\tiommu fault", (void *)pDehMgr)) == 0) + status = DSP_SOK; + else + status = DSP_EFAIL; + } + } + if (DSP_FAILED(status)) { + /* If create failed, cleanup */ + WMD_DEH_Destroy((struct DEH_MGR *)pDehMgr); + *phDehMgr = NULL; + } else { + *phDehMgr = (struct DEH_MGR *)pDehMgr; + DBG_Trace(DBG_LEVEL1, "ISR_IRQ Object 0x%x \n", + pDehMgr); + } + DBG_Trace(DBG_LEVEL1, "Exiting DEH_Create.\n"); + return status; +} + +/* + * ======== WMD_DEH_Destroy ======== + * Destroys DEH manager object. + */ +DSP_STATUS WMD_DEH_Destroy(struct DEH_MGR *hDehMgr) +{ + DSP_STATUS status = DSP_SOK; + struct DEH_MGR *pDehMgr = (struct DEH_MGR *)hDehMgr; + + DBG_Trace(DBG_LEVEL1, "Entering DEH_Destroy: 0x%x\n", pDehMgr); + if (MEM_IsValidHandle(pDehMgr, SIGNATURE)) { + /* Release dummy VA buffer */ + WMD_DEH_ReleaseDummyMem(); + /* If notification object exists, delete it */ + if (pDehMgr->hNtfy) + (void)NTFY_Delete(pDehMgr->hNtfy); + /* Disable DSP MMU fault */ + free_irq(INT_DSP_MMU_IRQ, pDehMgr); + (void)DPC_Destroy(pDehMgr->hMmuFaultDpc); + /* Deallocate the DEH manager object */ + MEM_FreeObject(pDehMgr); + } + DBG_Trace(DBG_LEVEL1, "Exiting DEH_Destroy.\n"); + return status; +} + +/* + * ======== WMD_DEH_RegisterNotify ======== + * Registers for DEH notifications. + */ +DSP_STATUS WMD_DEH_RegisterNotify(struct DEH_MGR *hDehMgr, u32 uEventMask, + u32 uNotifyType, + struct DSP_NOTIFICATION *hNotification) +{ + DSP_STATUS status = DSP_SOK; + struct DEH_MGR *pDehMgr = (struct DEH_MGR *)hDehMgr; + + DBG_Trace(DBG_LEVEL1, "Entering WMD_DEH_RegisterNotify: 0x%x\n", + pDehMgr); + + if (MEM_IsValidHandle(pDehMgr, SIGNATURE)) { + status = NTFY_Register(pDehMgr->hNtfy, hNotification, + uEventMask, uNotifyType); + } + DBG_Trace(DBG_LEVEL1, "Exiting WMD_DEH_RegisterNotify.\n"); + return status; +} + + +/* + * ======== WMD_DEH_Notify ======== + * DEH error notification function. Informs user about the error. + */ +void WMD_DEH_Notify(struct DEH_MGR *hDehMgr, u32 ulEventMask, + u32 dwErrInfo) +{ + struct DEH_MGR *pDehMgr = (struct DEH_MGR *)hDehMgr; + struct WMD_DEV_CONTEXT *pDevContext; + DSP_STATUS status = DSP_SOK; + DSP_STATUS status1 = DSP_EFAIL; + u32 memPhysical = 0; + u32 HW_MMU_MAX_TLB_COUNT = 31; + u32 extern faultAddr; + struct CFG_HOSTRES resources; + HW_STATUS hwStatus; + u32 NotifyStatus; + + status = CFG_GetHostResources( + (struct CFG_DEVNODE *)DRV_GetFirstDevExtension(), + &resources); + if (DSP_FAILED(status)) + DBG_Trace(DBG_LEVEL7, + "**Failed to get Host Resources in MMU ISR **\n"); + + DBG_Trace(DBG_LEVEL1, "Entering WMD_DEH_Notify: 0x%x, 0x%x\n", pDehMgr, + ulEventMask); + if (MEM_IsValidHandle(pDehMgr, SIGNATURE)) { + printk(KERN_INFO "WMD_DEH_Notify: ********** DEVICE EXCEPTION " + "**********\n"); + pDevContext = (struct WMD_DEV_CONTEXT *)pDehMgr->hWmdContext; + + switch (ulEventMask) { + case DSP_SYSERROR: + /* reset errInfo structure before use */ + pDehMgr->errInfo.dwErrMask = DSP_SYSERROR; + pDehMgr->errInfo.dwVal1 = 0L; + pDehMgr->errInfo.dwVal2 = 0L; + pDehMgr->errInfo.dwVal3 = 0L; + pDehMgr->errInfo.dwVal1 = dwErrInfo; + printk(KERN_ERR "WMD_DEH_Notify: DSP_SYSERROR, errInfo " + "= 0x%x\n", dwErrInfo); + break; + case DSP_MMUFAULT: + /* MMU fault routine should have set err info + * structure */ + pDehMgr->errInfo.dwErrMask = DSP_MMUFAULT; + printk(KERN_INFO "WMD_DEH_Notify: DSP_MMUFAULT," + "errInfo = 0x%x\n", dwErrInfo); + printk(KERN_INFO "WMD_DEH_Notify: DSP_MMUFAULT, High " + "Address = 0x%x\n", + (unsigned int)pDehMgr->errInfo.dwVal1); + printk(KERN_INFO "WMD_DEH_Notify: DSP_MMUFAULT, Low " + "Address = 0x%x\n", + (unsigned int)pDehMgr->errInfo.dwVal2); + printk(KERN_INFO "WMD_DEH_Notify: DSP_MMUFAULT, fault " + "address = 0x%x\n", (unsigned int)faultAddr); + dummyVaAddr = (u32)MEM_Calloc(sizeof(char) * 0x1000, + MEM_PAGED); + memPhysical = VirtToPhys(PG_ALIGN_LOW((u32)dummyVaAddr, + PG_SIZE_4K)); +DBG_Trace(DBG_LEVEL6, "WMD_DEH_Notify: DSP_MMUFAULT, " + "mem Physical= 0x%x\n", memPhysical); + pDevContext = (struct WMD_DEV_CONTEXT *) + pDehMgr->hWmdContext; + /* Reset the dynamic mmu index to fixed count if it + * exceeds 31. So that the dynmmuindex is always + * between the range of standard/fixed entries + * and 31. */ + if (pDevContext->numTLBEntries > + HW_MMU_MAX_TLB_COUNT) { + pDevContext->numTLBEntries = pDevContext-> + fixedTLBEntries; + } + DBG_Trace(DBG_LEVEL6, "Adding TLB Entry %d: VA: 0x%x, " + "PA: 0x%x\n", pDevContext-> + numTLBEntries, faultAddr, memPhysical); + if (DSP_SUCCEEDED(status)) { + hwStatus = HW_MMU_TLBAdd(resources.dwDmmuBase, + memPhysical, faultAddr, + HW_PAGE_SIZE_4KB, 1, &mapAttrs, + HW_SET, HW_SET); + } + /* send an interrupt to DSP */ +#ifdef OMAP_3430 + HW_MBOX_MsgWrite(resources.dwMboxBase, MBOX_ARM2DSP, + MBX_DEH_CLASS | MBX_DEH_EMMU); + +#else + NotifyStatus = notify_sendevent(handle,/*PROC_TESLA*/0, + /*eventNo*/4,MBX_DEH_CLASS | MBX_DEH_EMMU,true); +#endif + + + /* Clear MMU interrupt */ + HW_MMU_EventAck(resources.dwDmmuBase, + HW_MMU_TRANSLATION_FAULT); + break; + case DSP_PWRERROR: + /* reset errInfo structure before use */ + pDehMgr->errInfo.dwErrMask = DSP_PWRERROR; + pDehMgr->errInfo.dwVal1 = 0L; + pDehMgr->errInfo.dwVal2 = 0L; + pDehMgr->errInfo.dwVal3 = 0L; + pDehMgr->errInfo.dwVal1 = dwErrInfo; + printk(KERN_ERR "WMD_DEH_Notify: DSP_PWRERROR, errInfo " + "= 0x%x\n", dwErrInfo); + break; + default: + DBG_Trace(DBG_LEVEL6, + "WMD_DEH_Notify: Unknown Error, errInfo = " + "0x%x\n", dwErrInfo); + break; + } + + /* Filter subsequent notifications when an error occurs */ + if (pDevContext->dwBrdState != BRD_ERROR) { + /* Use it as a flag to send notifications the + * first time and error occurred, next time + * state will be BRD_ERROR */ + status1 = DSP_EFAIL; + } + + /* Filter subsequent notifications when an error occurs */ + if (pDevContext->dwBrdState != BRD_ERROR) + status1 = DSP_SOK; + + /* Set the Board state as ERROR */ + pDevContext->dwBrdState = BRD_ERROR; + /* Disable all the clocks that were enabled by DSP */ + (void)DSP_PeripheralClocks_Disable(pDevContext, NULL); + /* Call DSP Trace Buffer */ + PrintDspTraceBuffer(hDehMgr->hWmdContext); + + if (DSP_SUCCEEDED(status1)) { + /* Signal DSP error/exception event. */ + NTFY_Notify(pDehMgr->hNtfy, ulEventMask); + } + + } + DBG_Trace(DBG_LEVEL1, "Exiting WMD_DEH_Notify\n"); + +} + +/* + * ======== WMD_DEH_GetInfo ======== + * Retrieves error information. + */ +DSP_STATUS WMD_DEH_GetInfo(struct DEH_MGR *hDehMgr, + struct DSP_ERRORINFO *pErrInfo) +{ + DSP_STATUS status = DSP_SOK; + struct DEH_MGR *pDehMgr = (struct DEH_MGR *)hDehMgr; + + DBC_Require(pDehMgr); + DBC_Require(pErrInfo); + + DBG_Trace(DBG_LEVEL1, "Entering WMD_DEH_GetInfo: 0x%x\n", hDehMgr); + + if (MEM_IsValidHandle(pDehMgr, SIGNATURE)) { + /* Copy DEH error info structure to PROC error info + * structure. */ + pErrInfo->dwErrMask = pDehMgr->errInfo.dwErrMask; + pErrInfo->dwVal1 = pDehMgr->errInfo.dwVal1; + pErrInfo->dwVal2 = pDehMgr->errInfo.dwVal2; + pErrInfo->dwVal3 = pDehMgr->errInfo.dwVal3; + } + + DBG_Trace(DBG_LEVEL1, "Exiting WMD_DEH_GetInfo\n"); + + return status; +} + + +/* + * ======== WMD_DEH_ReleaseDummyMem ======== + * Releases memory allocated for dummy page + */ +void WMD_DEH_ReleaseDummyMem(void) +{ + if (dummyVaAddr) { + MEM_Free((void *)dummyVaAddr); + dummyVaAddr = 0; + } +} + |