static ssize_t wdt3_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t n) { u32 wdt3; struct DEV_OBJECT *dev_object; struct WMD_DEV_CONTEXT *dev_ctxt; if (sscanf(buf, "%d", &wdt3) != 1) return -EINVAL; dev_object = DEV_GetFirst(); if (dev_object == NULL) goto func_end; DEV_GetWMDContext(dev_object, &dev_ctxt); if (dev_ctxt == NULL) goto func_end; /* enable WDT */ if (wdt3 == 1) { if (dsp_wdt_get_enable()) goto func_end; dsp_wdt_set_enable(true); if (!CLK_Get_UseCnt(SERVICESCLK_wdt3_fck) && dev_ctxt->dwBrdState != BRD_DSP_HIBERNATION) dsp_wdt_enable(true); } else if (wdt3 == 0) { if (!dsp_wdt_get_enable()) goto func_end; if (CLK_Get_UseCnt(SERVICESCLK_wdt3_fck)) dsp_wdt_enable(false); dsp_wdt_set_enable(false); } func_end: return n; }
u32 MGRWRAP_Force_Recovery(union Trapped_Args *args, void *pr_ctxt) { DSP_STATUS status = DSP_SOK ; struct DEV_OBJECT *hDevObject; struct WMD_DEV_CONTEXT *dwContext; hDevObject = DEV_GetFirst(); /* default */ DEV_GetWMDContext(hDevObject, &dwContext); /* Set the Board state as ERROR */ dwContext->dwBrdState = BRD_ERROR; /* Disable all the clocks that were enabled by DSP */ (void)DSP_PeripheralClocks_Disable(dwContext, NULL); bridge_recovery_notify(DSP_SYSERROR) ; return status ; }
/* * ======== DMM_GetHandle ======== * Purpose: * Return the dynamic memory manager object for this device. * This is typically called from the client process. */ DSP_STATUS DMM_GetHandle(DSP_HPROCESSOR hProcessor, OUT struct DMM_OBJECT **phDmmMgr) { DSP_STATUS status = DSP_SOK; struct DEV_OBJECT *hDevObject; GT_2trace(DMM_debugMask, GT_ENTER, "DMM_GetHandle: hProcessor %x, phDmmMgr" "%x\n", hProcessor, phDmmMgr); DBC_Require(cRefs > 0); DBC_Require(phDmmMgr != NULL); if (hProcessor != NULL) status = PROC_GetDevObject(hProcessor, &hDevObject); else hDevObject = DEV_GetFirst(); /* default */ if (DSP_SUCCEEDED(status)) status = DEV_GetDmmMgr(hDevObject, phDmmMgr); GT_2trace(DMM_debugMask, GT_4CLASS, "Leaving DMM_GetHandle status %x, " "*phDmmMgr %x\n", status, phDmmMgr ? *phDmmMgr : NULL); return status; }
/* * ======== WCD_InitComplete2 ======== * Purpose: * Perform any required WCD, and WMD initialization which * cannot not be performed in WCD_Init() or DEV_StartDevice() due * to the fact that some services are not yet * completely initialized. * Parameters: * Returns: * DSP_SOK: Allow this device to load * DSP_EFAIL: Failure. * Requires: * WCD initialized. * Ensures: */ DSP_STATUS WCD_InitComplete2(void) { DSP_STATUS status = DSP_SOK; struct CFG_DEVNODE *DevNode; struct DEV_OBJECT *hDevObject; u32 devType; DBC_Require(WCD_cRefs > 0); GT_0trace(WCD_debugMask, GT_ENTER, "Entered WCD_InitComplete\n"); /* Walk the list of DevObjects, get each devnode, and attempting to * autostart the board. Note that this requires COF loading, which * requires KFILE. */ for (hDevObject = DEV_GetFirst(); hDevObject != NULL; hDevObject = DEV_GetNext(hDevObject)) { if (DSP_FAILED(DEV_GetDevNode(hDevObject, &DevNode))) continue; if (DSP_FAILED(DEV_GetDevType(hDevObject, &devType))) continue; if ((devType == DSP_UNIT) || (devType == IVA_UNIT)) { if (DSP_FAILED(PROC_AutoStart(DevNode, hDevObject))) { GT_0trace(WCD_debugMask, GT_1CLASS, "WCD_InitComplete2 Failed\n"); status = DSP_EFAIL; /* break; */ } } else GT_1trace(WCD_debugMask, GT_ENTER, "Ignoring PROC_AutoStart " "for Device Type = 0x%x \n", devType); } /* End For Loop */ GT_1trace(WCD_debugMask, GT_ENTER, "Exiting WCD_InitComplete status 0x%x\n", status); return status; }
/* * ======== WMD_CHNL_AddIOReq ======== * Enqueue an I/O request for data transfer on a channel to the DSP. * The direction (mode) is specified in the channel object. Note the DSP * address is specified for channels opened in direct I/O mode. */ DSP_STATUS WMD_CHNL_AddIOReq(struct CHNL_OBJECT *hChnl, void *pHostBuf, u32 cBytes, u32 cBufSize, OPTIONAL u32 dwDspAddr, u32 dwArg) { DSP_STATUS status = DSP_SOK; struct CHNL_OBJECT *pChnl = (struct CHNL_OBJECT *)hChnl; struct CHNL_IRP *pChirp = NULL; struct WMD_DEV_CONTEXT *dev_ctxt; struct DEV_OBJECT *dev_obj; u32 dwState; bool fIsEOS; struct CHNL_MGR *pChnlMgr = pChnl->pChnlMgr; u8 *pHostSysBuf = NULL; bool fSchedDPC = false; u16 wMbVal = 0; fIsEOS = (cBytes == 0); /* Validate args: */ if (pHostBuf == NULL) { status = DSP_EPOINTER; } else if (!MEM_IsValidHandle(pChnl, CHNL_SIGNATURE)) { status = DSP_EHANDLE; } else if (fIsEOS && CHNL_IsInput(pChnl->uMode)) { status = CHNL_E_NOEOS; } else { /* Check the channel state: only queue chirp if channel state * allows */ dwState = pChnl->dwState; if (dwState != CHNL_STATEREADY) { if (dwState & CHNL_STATECANCEL) status = CHNL_E_CANCELLED; else if ((dwState & CHNL_STATEEOS) && CHNL_IsOutput(pChnl->uMode)) status = CHNL_E_EOS; else /* No other possible states left: */ DBC_Assert(0); } } dev_obj = DEV_GetFirst(); DEV_GetWMDContext(dev_obj, &dev_ctxt); if (!dev_ctxt) status = DSP_EHANDLE; if (DSP_FAILED(status)) goto func_end; if (pChnl->uChnlType == CHNL_PCPY && pChnl->uId > 1 && pHostBuf) { if (!(pHostBuf < (void *)USERMODE_ADDR)) { pHostSysBuf = pHostBuf; goto func_cont; } /* if addr in user mode, then copy to kernel space */ pHostSysBuf = MEM_Alloc(cBufSize, MEM_NONPAGED); if (pHostSysBuf == NULL) { status = DSP_EMEMORY; goto func_end; } if (CHNL_IsOutput(pChnl->uMode)) { status = copy_from_user(pHostSysBuf, pHostBuf, cBufSize); if (status) { kfree(pHostSysBuf); pHostSysBuf = NULL; status = DSP_EPOINTER; goto func_end; } } } func_cont: /* Mailbox IRQ is disabled to avoid race condition with DMA/ZCPY * channels. DPCCS is held to avoid race conditions with PCPY channels. * If DPC is scheduled in process context (IO_Schedule) and any * non-mailbox interrupt occurs, that DPC will run and break CS. Hence * we disable ALL DPCs. We will try to disable ONLY IO DPC later. */ SYNC_EnterCS(pChnlMgr->hCSObj); omap_mbox_disable_irq(dev_ctxt->mbox, IRQ_RX); if (pChnl->uChnlType == CHNL_PCPY) { /* This is a processor-copy channel. */ if (DSP_SUCCEEDED(status) && CHNL_IsOutput(pChnl->uMode)) { /* Check buffer size on output channels for fit. */ if (cBytes > IO_BufSize(pChnl->pChnlMgr->hIOMgr)) status = CHNL_E_BUFSIZE; } } if (DSP_SUCCEEDED(status)) { /* Get a free chirp: */ pChirp = (struct CHNL_IRP *)LST_GetHead(pChnl->pFreeList); if (pChirp == NULL) status = CHNL_E_NOIORPS; } if (DSP_SUCCEEDED(status)) { /* Enqueue the chirp on the chnl's IORequest queue: */ pChirp->pHostUserBuf = pChirp->pHostSysBuf = pHostBuf; if (pChnl->uChnlType == CHNL_PCPY && pChnl->uId > 1) pChirp->pHostSysBuf = pHostSysBuf; /* * Note: for dma chans dwDspAddr contains dsp address * of SM buffer. */ DBC_Assert(pChnlMgr->uWordSize != 0); /* DSP address */ pChirp->uDspAddr = dwDspAddr / pChnlMgr->uWordSize; pChirp->cBytes = cBytes; pChirp->cBufSize = cBufSize; /* Only valid for output channel */ pChirp->dwArg = dwArg; pChirp->status = (fIsEOS ? CHNL_IOCSTATEOS : CHNL_IOCSTATCOMPLETE); LST_PutTail(pChnl->pIORequests, (struct list_head *)pChirp); pChnl->cIOReqs++; DBC_Assert(pChnl->cIOReqs <= pChnl->cChirps); /* If end of stream, update the channel state to prevent * more IOR's: */ if (fIsEOS) pChnl->dwState |= CHNL_STATEEOS; /* Legacy DSM Processor-Copy */ DBC_Assert(pChnl->uChnlType == CHNL_PCPY); /* Request IO from the DSP */ IO_RequestChnl(pChnlMgr->hIOMgr, pChnl, (CHNL_IsInput(pChnl->uMode) ? IO_INPUT : IO_OUTPUT), &wMbVal); fSchedDPC = true; } omap_mbox_enable_irq(dev_ctxt->mbox, IRQ_RX); SYNC_LeaveCS(pChnlMgr->hCSObj); if (wMbVal != 0) IO_IntrDSP2(pChnlMgr->hIOMgr, wMbVal); /* Schedule a DPC, to do the actual data transfer: */ if (fSchedDPC) IO_Schedule(pChnlMgr->hIOMgr); func_end: return status; }
/* * ======== WMD_CHNL_GetIOC ======== * Optionally wait for I/O completion on a channel. Dequeue an I/O * completion record, which contains information about the completed * I/O request. * Note: Ensures Channel Invariant (see notes above). */ DSP_STATUS WMD_CHNL_GetIOC(struct CHNL_OBJECT *hChnl, u32 dwTimeOut, OUT struct CHNL_IOC *pIOC) { DSP_STATUS status = DSP_SOK; struct CHNL_OBJECT *pChnl = (struct CHNL_OBJECT *)hChnl; struct CHNL_IRP *pChirp; DSP_STATUS statSync; bool fDequeueIOC = true; struct CHNL_IOC ioc = { NULL, 0, 0, 0, 0 }; u8 *pHostSysBuf = NULL; struct WMD_DEV_CONTEXT *dev_ctxt; struct DEV_OBJECT *dev_obj; /* Check args: */ if (pIOC == NULL) { status = DSP_EPOINTER; } else if (!MEM_IsValidHandle(pChnl, CHNL_SIGNATURE)) { status = DSP_EHANDLE; } else if (dwTimeOut == CHNL_IOCNOWAIT) { if (LST_IsEmpty(pChnl->pIOCompletions)) status = CHNL_E_NOIOC; } dev_obj = DEV_GetFirst(); DEV_GetWMDContext(dev_obj, &dev_ctxt); if (!dev_ctxt) status = DSP_EHANDLE; if (DSP_FAILED(status)) goto func_end; ioc.status = CHNL_IOCSTATCOMPLETE; if (dwTimeOut != CHNL_IOCNOWAIT && LST_IsEmpty(pChnl->pIOCompletions)) { if (dwTimeOut == CHNL_IOCINFINITE) dwTimeOut = SYNC_INFINITE; statSync = SYNC_WaitOnEvent(pChnl->hSyncEvent, dwTimeOut); if (statSync == DSP_ETIMEOUT) { /* No response from DSP */ ioc.status |= CHNL_IOCSTATTIMEOUT; fDequeueIOC = false; } else if (statSync == DSP_EFAIL) { /* This can occur when the user mode thread is * aborted (^C), or when _VWIN32_WaitSingleObject() * fails due to unkown causes. */ /* Even though Wait failed, there may be something in * the Q: */ if (LST_IsEmpty(pChnl->pIOCompletions)) { ioc.status |= CHNL_IOCSTATCANCEL; fDequeueIOC = false; } } } /* See comment in AddIOReq */ SYNC_EnterCS(pChnl->pChnlMgr->hCSObj); omap_mbox_disable_irq(dev_ctxt->mbox, IRQ_RX); if (fDequeueIOC) { /* Dequeue IOC and set pIOC; */ DBC_Assert(!LST_IsEmpty(pChnl->pIOCompletions)); pChirp = (struct CHNL_IRP *)LST_GetHead(pChnl->pIOCompletions); /* Update pIOC from channel state and chirp: */ if (pChirp) { pChnl->cIOCs--; /* If this is a zero-copy channel, then set IOC's pBuf * to the DSP's address. This DSP address will get * translated to user's virtual addr later. */ { pHostSysBuf = pChirp->pHostSysBuf; ioc.pBuf = pChirp->pHostUserBuf; } ioc.cBytes = pChirp->cBytes; ioc.cBufSize = pChirp->cBufSize; ioc.dwArg = pChirp->dwArg; ioc.status |= pChirp->status; /* Place the used chirp on the free list: */ LST_PutTail(pChnl->pFreeList, (struct list_head *)pChirp); } else { ioc.pBuf = NULL; ioc.cBytes = 0; } } else { ioc.pBuf = NULL; ioc.cBytes = 0; ioc.dwArg = 0; ioc.cBufSize = 0; } /* Ensure invariant: If any IOC's are queued for this channel... */ if (!LST_IsEmpty(pChnl->pIOCompletions)) { /* Since DSPStream_Reclaim() does not take a timeout * parameter, we pass the stream's timeout value to * WMD_CHNL_GetIOC. We cannot determine whether or not * we have waited in User mode. Since the stream's timeout * value may be non-zero, we still have to set the event. * Therefore, this optimization is taken out. * * if (dwTimeOut == CHNL_IOCNOWAIT) { * ... ensure event is set.. * SYNC_SetEvent(pChnl->hSyncEvent); * } */ SYNC_SetEvent(pChnl->hSyncEvent); } else { /* else, if list is empty, ensure event is reset. */ SYNC_ResetEvent(pChnl->hSyncEvent); } omap_mbox_enable_irq(dev_ctxt->mbox, IRQ_RX); SYNC_LeaveCS(pChnl->pChnlMgr->hCSObj); if (fDequeueIOC && (pChnl->uChnlType == CHNL_PCPY && pChnl->uId > 1)) { if (!(ioc.pBuf < (void *) USERMODE_ADDR)) goto func_cont; /* If the addr is in user mode, then copy it */ if (!pHostSysBuf || !ioc.pBuf) { status = DSP_EPOINTER; goto func_cont; } if (!CHNL_IsInput(pChnl->uMode)) goto func_cont1; /*pHostUserBuf */ status = copy_to_user(ioc.pBuf, pHostSysBuf, ioc.cBytes); if (status) { if (current->flags & PF_EXITING) status = 0; } if (status) status = DSP_EPOINTER; func_cont1: kfree(pHostSysBuf); } func_cont: /* Update User's IOC block: */ *pIOC = ioc; func_end: return status; }