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;
}
/*
 * this sysfs is intended to retrieve two MPU addresses
 * needed for the INST2 utility.
 * the inst_log script will run this sysfs
 */
static ssize_t mpu_address_show(struct device *dev,
			struct device_attribute *attr, char *buf)
{
    struct WMD_DEV_CONTEXT *dwContext = NULL;
	struct DEV_OBJECT *hDevObject = NULL;
	u32 mem_poolsize = 0;
	u32 GppPa = 0, DspVa = 0;
	u32 armPhyMemOffUncached = 0;
	hDevObject = (struct DEV_OBJECT *)DRV_GetFirstDevObject();
	DEV_GetWMDContext(hDevObject, &dwContext);
	if (!dwContext)
		return 0;
	GppPa = dwContext->aTLBEntry[0].ulGppPa;
	DspVa = dwContext->aTLBEntry[0].ulDspVa;

	/*
	 * the physical address offset, this offset is a
	 * fixed value for a given platform.
	 */
	armPhyMemOffUncached = GppPa - DspVa;

	/*
	 * the offset value for cached address region
	 * on DSP address space
	 */
	mem_poolsize = phys_mempool_base - 0x20000000;

	/* Retrive the above calculated addresses */
	return sprintf(buf, "mempoolsizeOffset 0x%x GppPaOffset 0x%x\n",
					mem_poolsize, armPhyMemOffUncached);
}
Example #3
0
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 ;
}
/*
 * sysfs
 */
static ssize_t drv_state_show(struct device *dev,
			struct device_attribute *attr, char *buf)
{
	struct WMD_DEV_CONTEXT *dwContext;
	struct DEV_OBJECT *hDevObject = NULL;
	int drv_state = 0;

	for (hDevObject = (struct DEV_OBJECT *)DRV_GetFirstDevObject();
		hDevObject != NULL;
		hDevObject = (struct DEV_OBJECT *)DRV_GetNextDevObject
							((u32)hDevObject)) {
		DEV_GetWMDContext(hDevObject, &dwContext);
		if (!dwContext)
			continue;

		drv_state = dwContext->dwBrdState;
	}

	return sprintf(buf, "%d\n", drv_state);
}
Example #5
0
/*
 *  ======== 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;

	 /*  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 */
		status = NTFY_Create(&pDehMgr->hNtfy);

		/* Create a MMUfault DPC */
		tasklet_init(&pDehMgr->dpc_tasklet, MMU_FaultDpc, (u32)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 {
		timer = omap_dm_timer_request_specific(
					GPTIMER_FOR_DSP_MMU_FAULT);
		if (timer)
			omap_dm_timer_disable(timer);
		else {
			pr_err("%s:GPTimer not available\n", __func__);
			return -ENODEV;
		}
		*phDehMgr = (struct DEH_MGR *)pDehMgr;
	}

	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;
}