void IPC_FreeBuffer(IPC_Buffer Buffer)
{
	IPC_Buffer_T *BufferPtr = IPC_BufferToPtr(Buffer);
	IPC_CPU_ID_T OwningCpu;

	if (BufferPtr == 0) {
		IPC_TRACE(IPC_Channel_Error, "IPC_FreeBuffer",
			  "Invalid Buffer %08X", Buffer, 0, 0, 0);
		return;
	}

	if (BufferPtr->StatusCode == IPC_BUFFER_STATUS_FREE) {
		IPC_TRACE(IPC_Channel_Error, "IPC_FreeBuffer",
			  "Repeated Free Buffer %08X", Buffer, 0, 0, 0);
		return;
	}

	OwningCpu = IPC_PoolOwningCpu(BufferPtr->Pool);
	BufferPtr->TimeStampFree = TIMER_GetValue();
	BufferPtr->StatusCode = IPC_BUFFER_STATUS_FREE;

	if (OwningCpu == IPC_SM_CURRENT_CPU) {
		IPC_TRACE(IPC_Channel_Buffer, "IPC_FreeBuffer",
			  "Buffer %08X, ID %d Same CPU ", Buffer,
			  BufferPtr->BufferId, 0, 0);
		IPC_BufferReturn(Buffer, BufferPtr->Pool);
	} else {
		IPC_TRACE(IPC_Channel_Buffer, "IPC_FreeBuffer",
			  "Buffer %08X, ID %d Other CPU", Buffer,
			  BufferPtr->BufferId, 0, 0);
		IPC_SmFreeBuffer(Buffer, OwningCpu);
	}
}
void IPC_ProcessEvents(void)
{
	IPC_Buffer Buffer;
	IPC_CPU_ID_T Cpu = IPC_SM_CURRENT_CPU;

	IPC_TRACE(IPC_Channel_Hisr, "IPC_ProcessEvents", "CPU %02X", Cpu, 0, 0,
		  0);

	if (!SmLocalControl.ConfiguredReported) {

		if ((SmLocalControl.SmControl->
		     Initialised[IPC_CPU_ID_INDEX(Cpu)] == IPC_SmConfigured)
		    && (SmLocalControl.SmControl->
			Initialised[IPC_CPU_ID_INDEX(IPC_OTHER_CPU[Cpu])] ==
			IPC_SmConfigured)) {
			SmLocalControl.ConfiguredReported = IPC_TRUE;
			(*SmLocalControl.IPCInitialisedFunction) ();
		} else {
			IPC_TRACE(IPC_Channel_Error, "IPC_ProcessEvents",
				  "CPU %02X, Not Initialised", Cpu, 0, 0, 0);
			return;
		}
	}
#ifdef FUSE_IPC_CRASH_SUPPORT
	if ((Cpu == IPC_AP_CPU) && (g_bCpCrashed == IPC_FALSE)
	    && (SmLocalControl.SmControl->CrashCode != IPC_CP_NOT_CRASHED)) {
		/* CP has crashed so set the crash status */
		g_bCpCrashed = IPC_TRUE;

		/**
		 * CP should be analysing crach here as this is the first
		 * indication - but call crash function in case finished.
		 */
		if (SmLocalControl.IPCCPCrashed)
			SmLocalControl.IPCCPCrashed(SmLocalControl.SmControl->
						    CrashCode);

	}

	if (g_bCpCrashed == IPC_TRUE) {
		if ((SmLocalControl.SmControl->CrashCode !=
		     IPC_CP_ANALYSING_CRASH)
		    && (SmLocalControl.SmControl->CrashCode !=
			IPC_CP_NOT_CRASHED)) {

			/**
			 * if CP is not analysing any more than we should
			 * have crash dump now
			 *
			 * call the function to handle the crash dump
			 */
			if (SmLocalControl.IPCCPCrashed)
				SmLocalControl.IPCCPCrashed(SmLocalControl.
							    SmControl->
							    CrashCode);
			/**
			 * This function can call  IPCAP_GetCrashData to get
			 * crash location.
			 */
		} else {
			g_bCpCrashed = IPC_FALSE;
		}
	} else
#endif /* FUSE_IPC_CRASH_SUPPORT */
	{
		{
			IPC_Fifo SendFifo = SmLocalControl.SendFifo;

			while (0 != (Buffer = IPC_SmFifoRead(SendFifo))) {
				IPC_EndpointId_T DestinationEpId =
				    IPC_PoolDestinationEndpointId
				    (IPC_BufferOwningPool(Buffer));
				IPC_Endpoint DestinationEpPtr =
				    IPC_SmEndpointInfo(DestinationEpId);

#ifdef IPC_DEBUG
				if (DestinationEpPtr
				    && DestinationEpPtr->DeliveryFunction
				    && DestinationEpPtr->Cpu ==
				    IPC_SM_CURRENT_CPU) {
					IPC_TRACE(IPC_Channel_Hisr,
						  "IPC_ProcessEvents",
						  "Buffer %08X, size %d, EP %d, Fn %08X",
						  Buffer,
						  IPC_BufferDataSize(Buffer),
						  DestinationEpId,
						  (IPC_U32) DestinationEpPtr->
						  DeliveryFunction);

					(DestinationEpPtr->
					 DeliveryFunction) (Buffer);

				} else {
					IPC_TRACE(IPC_Channel_Error,
						  "IPC_ProcessEvents",
						  "No Delivery Function for EP %d, Function %08X, CpuId %d",
						  DestinationEpId,
						  (IPC_U32) DestinationEpPtr->
						  DeliveryFunction,
						  DestinationEpPtr->Cpu, 0);

					IPC_FreeBuffer(Buffer);
				}
#else
				(DestinationEpPtr->DeliveryFunction) (Buffer);
#endif
			}
		}
		{

			IPC_Fifo FreeFifo = SmLocalControl.FreeFifo;
			while (0 != (Buffer = IPC_SmFifoRead(FreeFifo))) {
				IPC_BufferReturn(Buffer,
						 IPC_BufferOwningPool(Buffer));
			}
		}
	}
}