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);
	}
}
Exemple #2
0
const char *show_box_cb(guiObject_t *obj, const void *data)
{
    (void)obj;
    u8 idx = (long)data;
    #if HAS_RTC
        if (idx <= NUM_RTC) {
            u32 time = RTC_GetValue();
            idx == 1 ? RTC_GetTimeFormatted(tempstring, time) : RTC_GetDateFormatted(tempstring, time);
            return tempstring;
        }
    #endif
    if (idx - NUM_RTC <= NUM_TIMERS) {
        TIMER_SetString(tempstring, TIMER_GetValue(idx - NUM_RTC - 1));
    } else if(idx - NUM_RTC - NUM_TIMERS <= NUM_TELEM) {
        TELEMETRY_GetValueStr(tempstring, idx - NUM_RTC - NUM_TIMERS);
    } else {
        unsigned channel = idx - (NUM_RTC + NUM_TIMERS + NUM_TELEM + 1);
        s16 val_raw = MIXER_GetChannel(channel, APPLY_SAFETY | APPLY_SCALAR);
        s16 val_scale = MIXER_GetChannelDisplayScale(channel);
        const char* val_format = MIXER_GetChannelDisplayFormat(channel);

        sprintf(tempstring, val_format, val_raw/val_scale);
    }
    return tempstring;
}
IPC_ReturnCode_T IPC_SendBuffer(IPC_Buffer Buffer, IPC_Priority_T Priority)
{
	IPC_Buffer_T *BufferPtr = IPC_BufferToPtr(Buffer);

	IPC_TRACE(IPC_Channel_Buffer, "IPC_SendBuffer",
		  "Buffer %d (%08X), Priority %d", BufferPtr->BufferId, Buffer,
		  Priority, 0);

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

	BufferPtr->TimeStampSend = TIMER_GetValue();
	BufferPtr->StatusCode = IPC_BUFFER_STATUS_SENT;

	IPC_PoolAddBytesSent(BufferPtr->Pool,
			     BufferPtr->DataSize + BufferPtr->HeaderSize);

#ifdef IPC_BUFFER_STATS
	/* Debug output - turned off by default for performance */
	if (BufferPtr->BufferId == 0 && 0 == LISR_Active)
		IPC_PoolDumpStats(BufferPtr->Pool);
#endif

	IPC_SmSendBuffer(Buffer);

	return IPC_OK;
}
/****************************************************************
*   Called from the IPC interrupt service thread in ipc_server.c
*   to check if CP has crashed.
*
*	@return int		0 if CP not crashed, 1 otherwise
*
*****************************************************************/
int IpcCPCrashCheck(void)
{
	IPC_CrashCode_T CpCrashReason;
	IPC_U32 *Dump;
	crashCount = 0;

	if (!SmLocalControl.ConfiguredReported) {
		IPC_DEBUG(DBG_TRACE, "IPC Not Initialised\n");
		return 0;
	}

	/* Get the crash reason and crash dump location */
	CpCrashReason = SmLocalControl.SmControl->CrashCode;
	Dump = (void *)SmLocalControl.SmControl->CrashDump;

	if (IPC_CP_NOT_CRASHED != CpCrashReason &&
	    IPC_CP_MAX_CRASH_CODE > CpCrashReason && NULL != Dump) {
		crashCount++;
		IPC_DEBUG(DBG_ERROR,
			  "CP Crashed!! CP Ticks[%ld] reason:%d count:%d Dump:0x%X\n",
			  TIMER_GetValue(), CpCrashReason, crashCount,
			  (unsigned int)Dump);

		if (crashCount > 1)
			return 0;

		return 1;
	}

	return 0;
}
static void IPC_RaiseInterrupt(void)
{
	IPC_U32 Cpu = IPC_CPU_ID_INDEX(IPC_SM_CURRENT_CPU);
	IPC_U32	IrqRaised = SmLocalControl.SmControl->IrqCounts[Cpu].IrqRaised; 

	SmLocalControl.SmControl->IrqTime[Cpu][IrqRaised % 4].IrqRaiseTime
		 = TIMER_GetValue();
	SmLocalControl.SmControl->IrqCounts[Cpu].IrqRaised++; 

	(*SmLocalControl.RaiseInterrupt)();
}
int RpcLog_DebugPrintf(char* fmt, ...)
{
#if 0 // blocked RPC LOG - jaesub.kim
#ifdef CONFIG_BRCM_UNIFIED_LOGGING
    va_list ap;
    va_start(ap, fmt);
    vsnprintf(buf, MAX_BUF_SIZE, fmt, ap);
    va_end(ap);
    KRIL_DEBUG(DBG_INFO, "TS[%ld]%s\n", TIMER_GetValue(), buf);
#else
    if(IsBasicCapi2LoggingEnable())
    {
        va_list ap;
        va_start(ap, fmt);
        vsnprintf(buf, MAX_BUF_SIZE, fmt, ap);
        va_end(ap);
        pr_info("TS[%ld]%s",TIMER_GetValue(),buf);
    }
#endif
#endif
    return 1;
}
void IPC_ApSleepModeSet(IPC_Boolean inSleep)
{
	static IPC_U32	sleepCount = 0; 
	static IPC_U32	resumeCount = 0; 

	if (!inSleep)
	{
		IPC_AlignTime();
		SmLocalControl.SmControl->ApSleepTime[resumeCount % 4].ResumeTime 
			= TIMER_GetValue();
		resumeCount ++;
	}
	else
	{
		SmLocalControl.SmControl->ApSleepTime[sleepCount % 4].SleepTime 
			= TIMER_GetValue();
		sleepCount ++;
	}
	IPC_TRACE(IPC_Channel_General, "IPC_ApSleepModeSet",
		"state %d time %u", 
		inSleep, TIMER_GetValue(), 0, 0);
}
Exemple #8
0
s32 get_boxval(u8 idx)
{
#if HAS_RTC
    if (idx <= NUM_RTC) {
        u32 time = RTC_GetValue();
        return idx == 1 ? RTC_GetTimeValue(time) : RTC_GetDateValue(time);
    }
#endif
    if (idx - NUM_RTC <= NUM_TIMERS)
        return TIMER_GetValue(idx - NUM_RTC - 1);
    if(idx - NUM_RTC - NUM_TIMERS <= NUM_TELEM)
        return TELEMETRY_GetValue(idx - NUM_RTC - NUM_TIMERS);
    return RANGE_TO_PCT(MIXER_GetChannel(idx - (NUM_RTC + NUM_TIMERS + NUM_TELEM + 1), APPLY_SAFETY | APPLY_SCALAR));
}
Exemple #9
0
const char *show_box_cb(guiObject_t *obj, const void *data)
{
    (void)obj;
    u8 idx = (long)data;
    #if HAS_RTC
        if (idx <= NUM_RTC) {
            u32 time = RTC_GetValue();
            idx == 1 ? RTC_GetTimeFormatted(tempstring, time) : RTC_GetDateFormatted(tempstring, time);
            return tempstring;
        }
    #endif
    if (idx - NUM_RTC <= NUM_TIMERS) {
        TIMER_SetString(tempstring, TIMER_GetValue(idx - NUM_RTC - 1));
    } else if(idx - NUM_RTC - NUM_TIMERS <= NUM_TELEM) {
        TELEMETRY_GetValueStr(tempstring, idx - NUM_RTC - NUM_TIMERS);
    } else {
        sprintf(tempstring, "%3d%%", RANGE_TO_PCT(MIXER_GetChannel(idx - (NUM_RTC + NUM_TIMERS + NUM_TELEM + 1), APPLY_SAFETY | APPLY_SCALAR)));
    }
    return tempstring;
}
void IPC_UpdateIrqStats(void)
{
	IPC_U32 Cpu, PeerCpu;
	IPC_U32	IrqHandled, PeerIrqRaised; 
	
	Cpu = IPC_CPU_ID_INDEX(IPC_SM_CURRENT_CPU);
	if (IPC_SM_CURRENT_CPU == IPC_AP_CPU) {
		PeerCpu = IPC_CPU_ID_INDEX(IPC_CP_CPU);
	} else {
		PeerCpu = IPC_CPU_ID_INDEX(IPC_AP_CPU);
	}

	IrqHandled = SmLocalControl.SmControl->IrqCounts[Cpu].IrqHandled; 
	PeerIrqRaised = SmLocalControl.SmControl->IrqCounts[PeerCpu].IrqRaised; 

	SmLocalControl.SmControl->IrqTime[Cpu][IrqHandled % 4].IrqHandleTime
		= TIMER_GetValue();

	// save a copy of IRQ raise time to compare with IRQ handle time 
	SmLocalControl.SmControl->IrqTime[Cpu][IrqHandled % 4].IrqRaiseTimeCopy
		= SmLocalControl.SmControl->IrqTime[PeerCpu][(PeerIrqRaised + 3) % 4].IrqRaiseTime;

	SmLocalControl.SmControl->IrqCounts[Cpu].IrqHandled++;
}
/******************************************************************
*   Utility function to retrieve full crash log from CP via simple
*   handshake protocol.
*
*
********************************************************************/
void DUMP_CP_assert_log(void)
{
	UInt32 t1, i, size, retryCount;
	UInt8 *p;
	UInt32 packetCount = 0;
	void __iomem *AssertLogVAddr = NULL;
	struct file *sdDumpFile = NULL;
	int cpReset = SmLocalControl.SmControl->CrashCode ==
	    IPC_CP_SILENT_RESET_READY;

	/* put logging driver into crash dump mode; messages will be sent
	 * straight out to MTT via RNDIS (or dump file) instead of buffering
	 * in RING buffer (flood of crash dump info overloads ring buffer
	 * otherwise,and we lose a lot of crash dump info)
	 * NOTE: crash dump is put into SD by default; if SD file fails to open,
	 * then we'll try sending it out RNDIS */

	BCMLOG_StartCpCrashDump(sdDumpFile, cpReset);

	/* only grab RAM dump for CP reset case */
	if (!cpReset) {
		retryCount = 0;
		while (1) {
			t1 = TIMER_GetValue();

			/* signal to CP that we're ready to rx crash log... */
			SmLocalControl.SmControl->CrashCode =
			    IPC_AP_CLEAR_TO_SEND;

			/* wait for CP to "dump"; CrashCode field will be
			 * set to physical address of current assert buf */
			while (SmLocalControl.SmControl->CrashCode ==
			       IPC_AP_CLEAR_TO_SEND) {
				for (i = 0; i < 256; i++)
					;
				if (TIMER_GetValue() - t1 >
				    TICKS_ONE_SECOND * 20)
					break;
			}

			/* check for time out */
			if (SmLocalControl.SmControl->CrashCode ==
			    IPC_AP_CLEAR_TO_SEND) {
				if (retryCount < MAX_CP_DUMP_RETRIES) {
					retryCount++;
					IPC_DEBUG(
						DBG_TRACE,
						"timeout %d, trying again..\n",
						(int)retryCount);
					continue;
				} else {
					/* no response from CP,
					 * so get out of here
					 */
					IPC_DEBUG(
						DBG_ERROR,
						"Abort --- max retries %d reached\n",
						(int)retryCount);
					break;
				}
			}

			/* reset retry counter */
			retryCount = 0;

			/* get virtual address of CP assert buffer */
			AssertLogVAddr = ioremap_nocache(
					(UInt32)
					(SmLocalControl.SmControl->CrashCode),
					ASSERT_BUF_SIZE);
			if (NULL == AssertLogVAddr) {
				IPC_DEBUG(DBG_ERROR,
					  "ioremap_nocache failed in DUMP_CP_assert_log\n");
				break;
			}
			p = (UInt8 *)AssertLogVAddr;

			/* number of bytes in assert buffer */
			size = (p[0] << 8) + p[1];

			/* size of 0 means CP is done dumping assert log */
			if (size == 0) {
				IPC_DEBUG(DBG_ERROR,
					  "assert log size 0, exiting, packetCount:0x%x\n",
					  (int)packetCount);
				iounmap(AssertLogVAddr);
				AssertLogVAddr = NULL;
				break;
			}
			/* sanity check for too beaucoup... */
			if (size > ASSERT_BUF_SIZE - 2) {
				IPC_DEBUG(DBG_ERROR,
					  "Abort --- improper size [%08x]=%d\n",
					  SmLocalControl.SmControl->CrashCode,
					  (int)size);
				iounmap(AssertLogVAddr);
				AssertLogVAddr = NULL;
				break;
			}
			/* send packet out to log
			 * (MTT via RNDIS or crash dump file)
			 */
			BCMLOG_HandleCpCrashDumpData((const char *)(p + 2),
						     size);

			packetCount++;
			iounmap(AssertLogVAddr);
			AssertLogVAddr = NULL;

		}
	}

	RpcDbgDumpHistoryLogging(2, 1);

	IPC_DEBUG(DBG_ERROR, "Starting CP RAM dump - do not power down...\n");

	/* dump all CP memory to log */
	DUMP_CPMemoryByList(dumped_crash_summary_ptr->mem_dump);

	IPC_DEBUG(DBG_ERROR, "CP RAM dump complete\n");
	/* resume normal logging activities... */
	BCMLOG_EndCpCrashDump();

	if (BCMLOG_OUTDEV_SDCARD == BCMLOG_GetCpCrashLogDevice())
		sys_sync();

	IPC_DEBUG(DBG_ERROR, "CP crash dump complete\n");

	if ((BCMLOG_OUTDEV_SDCARD == BCMLOG_GetCpCrashLogDevice())
	    && cp_crashed == 1 && !cpReset)
		abort();

}
/**	
*   Utility function to retrieve full crash log from CP via simple handshake
*   protocol.
*
*
********************************************************************************/
void DUMP_CP_assert_log(void)
{
	UInt32 t0, t1, i, size, retryCount;
	UInt8 *p;
	UInt32 packetCount = 0;
    void __iomem *AssertLogVAddr = NULL;
    struct file* sdDumpFile = NULL;
    mm_segment_t oldfs;
    struct timespec ts;
    struct rtc_time tm;
    char assertFileName[CP_CRASH_DUMP_MAX_LEN];
	extern void abort(void);
    
    // need to tell kernel that pointers from within the 
    // kernel address space are valid (needed to do 
    // file ops from kernel)
    oldfs = get_fs();     
    set_fs (KERNEL_DS); 

	if( BCMLOG_CPCRASH_SDCARD == BCMLOG_GetCpCrashDumpDevice() )
	{
    // get current time
    getnstimeofday(&ts);
    rtc_time_to_tm(ts.tv_sec, &tm);
    snprintf(assertFileName, CP_CRASH_DUMP_MAX_LEN,
            "%s%s%d_%02d_%02d_%02d_%02d_%02d%s",
            CP_CRASH_DUMP_DIR,
            CP_CRASH_DUMP_BASE_FILE_NAME,
            tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
            tm.tm_hour, tm.tm_min, tm.tm_sec,
            CP_CRASH_DUMP_FILE_EXT );

	sdDumpFile = filp_open( assertFileName, O_WRONLY|O_TRUNC|O_LARGEFILE|O_CREAT, 666);
	if ( IS_ERR(sdDumpFile)  )
	{
		IPC_DEBUG(DBG_ERROR,"failed to open sdDumpFile %s\n", assertFileName);
		sdDumpFile = NULL;
	}
	else
	{
		IPC_DEBUG(DBG_ERROR,"sdDumpFile %s opened OK\n",assertFileName);
	}
	}
       
    // put logging driver into crash dump mode; messages will be sent straight out to MTT via 
    // RNDIS (or dump file) instead of buffering in RING buffer (flood of crash dump info 
    // overloads ring buffer otherwise, and we lose a lot of crash dump info)
    // NOTE: crash dump is put into SD by default; if SD file fails to open, then we'll try 
    // sending it out RNDIS
    BCMLOG_StartCpCrashDump( sdDumpFile );
    
    retryCount = 0;
	t0 = TIMER_GetValue();
	while (1)
	{
		t1 = TIMER_GetValue();
		
		// signal to CP that we're ready to receive crash log...
		SmLocalControl.SmControl->CrashCode = IPC_AP_CLEAR_TO_SEND;
		
		// wait for CP to "dump"; CrashCode field will be set to physical address of current assert buf
		while (SmLocalControl.SmControl->CrashCode == IPC_AP_CLEAR_TO_SEND)
		{
			for (i=0; i<256; i++);
			if (TIMER_GetValue() - t1 > TICKS_ONE_SECOND * 20) break;
		}
		
		// check for time out
		if (SmLocalControl.SmControl->CrashCode == IPC_AP_CLEAR_TO_SEND)
		{
		    if ( retryCount < MAX_CP_DUMP_RETRIES )
		    {
		        retryCount++;
                IPC_DEBUG(DBG_ERROR,"timeout %d, trying again...\n", (int)retryCount);
		        continue;
		    }
		    else
		    {
    		    // no response from CP, so get out of here
                IPC_DEBUG(DBG_ERROR,"Abort --- max retries %d reached\n", (int)retryCount);
                break;
            }
		}
		
		// reset retry counter
		retryCount = 0;
		
		// get virtual address of CP assert buffer
        AssertLogVAddr = ioremap_nocache((UInt32)(SmLocalControl.SmControl->CrashCode), ASSERT_BUF_SIZE);
        if(NULL == AssertLogVAddr)
        {
            IPC_DEBUG(DBG_ERROR, "ioremap_nocache failed in DUMP_CP_assert_log\n");
            break;    
        }
		
		p = (UInt8 *)AssertLogVAddr;
		
		// number of bytes in assert buffer
		size = (p[0] << 8) + p[1];
		
		// size of 0 means CP is done dumping assert log
		if (size == 0)
		{
            IPC_DEBUG(DBG_INFO, "assert log size 0, exiting, packetCount:0x%x\n", (int)packetCount);
            iounmap(AssertLogVAddr);
            AssertLogVAddr = NULL;
		    break;
		}
		
		// sanity check for too beaucoup...
		if (size > ASSERT_BUF_SIZE - 2)
		{
            IPC_DEBUG(DBG_ERROR, "Abort --- improper size [%08x]=%d\n", SmLocalControl.SmControl->CrashCode, (int)size);
            iounmap(AssertLogVAddr);
            AssertLogVAddr = NULL;
			break;
		}
		
		// send packet out to log (MTT via RNDIS or crash dump file)
		BCMLOG_HandleCpCrashDumpData( (const char*)(p+2), size );

        packetCount++;
        iounmap(AssertLogVAddr);
		AssertLogVAddr = NULL;

#if 0	
        // **FIXME** this is Nucleus timeout code - do we want something similar 
        // for Android? Maybe if we get to the point of restarting CP with 
        // restarting AP	
		if (TIMER_GetValue() - t0 > TICKS_ONE_SECOND * 10 * 60)
		{
			IPC_DEBUG(DBG_ERROR,"Abort --- CP assertion log too long\n");
			break;
		}
#endif
	}
	
    IPC_DEBUG(DBG_ERROR,"Starting CP RAM dump - do not power down...\n");

	// dump all CP memory to log
    DUMP_CPMemoryByList( dumped_crash_summary_ptr->mem_dump );
    
    IPC_DEBUG(DBG_ERROR,"CP RAM dump complete\n");
    // resume normal logging activities...
    BCMLOG_EndCpCrashDump( );

    if ( sdDumpFile )
    {
        filp_close( sdDumpFile ,NULL );
    }
    set_fs (oldfs); 
 	sys_sync();
    IPC_DEBUG(DBG_ERROR,"CP crash dump complete\n");

	if (BCMLOG_CPCRASH_MTD != BCMLOG_GetCpCrashDumpDevice())
		abort();
#ifdef CONFIG_BRCM_KPANIC_UI_IND
	else
		lcdc_disp_img(IMG_INDEX_END_DUMP);  //parameter 1: Draw the Kpanic Dump complete picture
#endif

}
IPC_Buffer IPC_AllocateBufferWait(IPC_BufferPool Pool, IPC_U32 MilliSeconds)
{
	IPC_BufferPool_T *PoolPtr = IPC_PoolToPtr(Pool);
	IPC_Buffer Buffer;
	IPC_ReturnCode_T errCode;
	UInt32 curTick, endTick;
	UInt32 beforeTick, afterTick;

	curTick = 0;
	endTick = MilliSeconds;

	while (curTick < endTick) {
		/* Try straight allocate first
		   (saves event operations most of the time) */
		Buffer = IPC_AllocateBuffer(Pool);
		if (Buffer)
			return Buffer;

		/* Check Event exists */
		if (!PoolPtr->EmptyEvent) {
			/* Can't suspend without an event flag */
			IPC_TRACE(IPC_Channel_Error, "IPC_AllocateBufferWait",
				  "No Event Flag for Pool %08X", Pool, 0, 0, 0);
			return 0;
		}

		/* Clear event before waiting on it */
		if (IPC_OK != IPC_EVENT_CLEAR(PoolPtr->EmptyEvent)) {
			IPC_TRACE(IPC_Channel_Error, "IPC_AllocateBufferWait",
				  "Cannot clear Event Flag %08P for Pool %08X",
				  PoolPtr->EmptyEvent, Pool, 0, 0);
			return 0;
		}

		/* Check in case the event was set  before the clear */
		Buffer = IPC_AllocateBuffer(Pool);
		if (Buffer)
			return Buffer;

		/* Now can safely wait for the event to be set
		 * by the buffer free */
		IPC_TRACE(IPC_Channel_FlowControl, "IPC_AllocateBufferWait",
			  "Pool %08X Empty, waiting for %d Milliseconds, total=%d",
			  Pool, (endTick - curTick), MilliSeconds, 0);

		beforeTick = TIMER_GetValue();
		errCode =
		    IPC_EVENT_WAIT(PoolPtr->EmptyEvent, (endTick - curTick));
		afterTick = TIMER_GetValue();

		/* Handle wrap around for 0xFFFFFFFF */
		curTick += (UInt32)(afterTick - beforeTick);

		if (IPC_ERROR == errCode) {
			IPC_TRACE(IPC_Channel_Error, "IPC_AllocateBufferWait",
				  "Error from IPC_EVENT_WAIT; Event Flag %08P for Pool %08X",
				  PoolPtr->EmptyEvent, Pool, 0, 0);
			return 0;
		} else if (IPC_OK == errCode) {
			continue;	/* retry */
		} else {	/* IPC_TIMEOUT */
			break;
		}
	}

	return IPC_AllocateBuffer(Pool);
}
IPC_Buffer IPC_AllocateBuffer(IPC_BufferPool Pool)
{
	CRITICAL_REIGON_SETUP IPC_BufferPool_T *PoolPtr = IPC_PoolToPtr(Pool);
	IPC_SmQEntry QElement;
	IPC_U32 BufferCount;
	IPC_Buffer Buffer;
	IPC_Boolean FlowControlCallNeeded = IPC_FALSE;

	if (!Pool) {
		IPC_TRACE(IPC_Channel_Error, "IPC_AllocateBuffer",
			  "Invalid Pool %08X", Pool, 0, 0, 0);
		return 0;
	}

	CRITICAL_REIGON_ENTER(PoolPtr->Lock);

	QElement = IPC_QGetFirst(IPC_POOLFreeQ(Pool));

	if (!QElement) {
		PoolPtr->FlowControlState = IPC_FLOW_STOP;
		PoolPtr->AllocationFailures++;
		CRITICAL_REIGON_LEAVE(PoolPtr->Lock);

		if (PoolPtr->DestinationEndpointId != IPC_EP_LogApps)
			IPC_TRACE(IPC_Channel_FlowControl,
				  "IPC_ReportFlowControlEvent",
				  "Pool %08X Empty, Allocations %d AllocationFailures %d FlowStopCalls %d",
				  Pool, PoolPtr->Allocations,
				  PoolPtr->AllocationFailures,
				  PoolPtr->FlowStopCalls);
		return 0;
	}
#ifdef IPC_DEBUG
	IPC_QAddBack(QElement, IPC_SmOffset(&PoolPtr->AllocatedBufferQ));
#endif

	BufferCount = --PoolPtr->FreeBuffers;

	/* Flow Control Check */
	if (BufferCount == PoolPtr->FlowStopLimit)
		CHECK_FLOW_STATE(PoolPtr, IPC_FLOW_STOP, FlowControlCallNeeded)

		    CRITICAL_REIGON_LEAVE(PoolPtr->Lock);

	if (FlowControlCallNeeded)
		IPC_ReportFlowControlEvent(PoolPtr, IPC_FLOW_STOP);

	Buffer = IPC_QEntryPtr(QElement)->Item;
	if (Buffer) {
		IPC_Buffer_T *BufferPtr = IPC_SmOffsetToPointer(IPC_Buffer_T,
								Buffer);

		BufferPtr->HeaderSize = 0;
		BufferPtr->DataSize = 0;
		BufferPtr->UserParameter = 0;
		BufferPtr->TimeStampAlloc = TIMER_GetValue();
		BufferPtr->StatusCode = IPC_BUFFER_STATUS_ALLOC;
		BufferPtr->DataOffset = BufferPtr->DataBufferStart +
		    IPC_PoolPtr(BufferPtr->Pool)->MaxHeaderSize;
	}

	IPC_TRACE(IPC_Channel_Buffer, "IPC_AllocateBuffer",
		  "Buf %d (%08X) Pool %08X, %d Left", IPC_BufferId(Buffer),
		  Buffer, Pool, BufferCount);

	/* Update Statistics */
	PoolPtr->Allocations++;

	if (BufferCount < PoolPtr->LowWaterMark)
		PoolPtr->LowWaterMark = BufferCount;

	return Buffer;
}