void IPC_BufferReturnToPool(IPC_Buffer Buffer, IPC_BufferPool Pool) { IPC_BufferPool_T *PoolPtr = IPC_PoolToPtr(Pool); IPC_U32 BufferCount; IPC_Boolean FlowControlCallNeeded = IPC_FALSE; CRITICAL_REIGON_SETUP IPC_TRACE(IPC_Channel_Buffer, "IPC_BufferReturnToPool", "Buffer %d (%08X), now %d in pool", IPC_BufferId(Buffer), Buffer, PoolPtr->FreeBuffers + 1, 0); CRITICAL_REIGON_ENTER(PoolPtr->Lock); BufferCount = ++PoolPtr->FreeBuffers; #ifdef IPC_DEBUG IPC_QRemove(IPC_BufferQueue(Buffer)); #endif IPC_QAddBack(IPC_BufferQueue(Buffer), IPC_POOLFreeQ(IPC_SmOffset(PoolPtr))); /* Flow Control Check */ if (BufferCount == PoolPtr->FlowStartLimit) CHECK_FLOW_STATE(PoolPtr, IPC_FLOW_START, FlowControlCallNeeded) CRITICAL_REIGON_LEAVE(PoolPtr->Lock); if (FlowControlCallNeeded) IPC_ReportFlowControlEvent(PoolPtr, IPC_FLOW_START); /* Last ditch check - should never happen */ if (PoolPtr->FlowControlState == IPC_FLOW_STOP && !PoolPtr->FlowControlCallPending && PoolPtr->FlowStartLimit < BufferCount) { IPC_TRACE(IPC_Channel_FlowControl, "IPC_BufferReturnToPool", "Retry Flow Start", 0, 0, 0, 0); IPC_ReportFlowControlEvent(PoolPtr, IPC_FLOW_START); } /* For IPC_AllocateBufferWait () */ if ((BufferCount == 1) && (PoolPtr->EmptyEvent)) IPC_EVENT_SET(PoolPtr->EmptyEvent); }
//************************************************** IPC_BufferPool IPC_CreateBufferPoolWithDescriptor ( IPC_EndpointId_T SourceEndpointId, IPC_EndpointId_T DestinationEndpointId, IPC_U32 NumberOfBuffers, IPC_U32 BufferSize, IPC_U32 FlowStartLimit, IPC_U32 FlowStopLimit, IPC_U32 LocalDescriptorSize ) { IPC_U32 MaxDataSize = ALIGN4 (BufferSize); IPC_BufferPool Pool; IPC_BufferPool_T * PoolPtr; IPC_Endpoint DestinationEpPtr; IPC_SmPtr Buffer; IPC_U32 Id; char * LocalData; IPC_TRACE (IPC_Channel_Pool, "IPC_CreateBufferPool", "Source %02X, Destination %02X, Buffer Count %d, Buffer Size %d", SourceEndpointId, DestinationEndpointId, NumberOfBuffers, BufferSize); // Sanity Checks if (NumberOfBuffers == 0) { IPC_TRACE (IPC_Channel_Error, "IPC_CreateBufferPool", "Invalid NumberOfBuffers %d", NumberOfBuffers, 0, 0, 0); return 0; } if (!IPC_SmEndpointInfo (SourceEndpointId)) { IPC_TRACE (IPC_Channel_Error, "IPC_CreateBufferPool", "Invalid Source Endpoint %d", SourceEndpointId, 0, 0, 0); return 0; } if (0 == (DestinationEpPtr = IPC_SmEndpointInfo (DestinationEndpointId))) { IPC_TRACE (IPC_Channel_Error, "IPC_CreateBufferPool", "Invalid Destination Endpoint %d", DestinationEndpointId, 0, 0, 0); return 0; } if (FlowStartLimit > NumberOfBuffers) { IPC_TRACE (IPC_Channel_Error, "IPC_CreateBufferPool", "Invalid FlowStartLimit %d", FlowStartLimit, 0, 0, 0); return 0; } if (FlowStopLimit >= NumberOfBuffers) { IPC_TRACE (IPC_Channel_Error, "IPC_CreateBufferPool", "Invalid FlowStopLimit %d", FlowStopLimit, 0, 0, 0); return 0; } // Allocate Sm For Pool Pool = IPC_SmPoolAlloc (sizeof (IPC_BufferPool_T), DestinationEpPtr->MaxHeaderSize, MaxDataSize, NumberOfBuffers); if (!Pool) { IPC_TRACE (IPC_Channel_Error, "IPC_CreateBufferPool", "IPC_SmPoolAlloc Failed", 0, 0, 0, 0); return 0; } if (LocalDescriptorSize != 0) { #ifdef UNDER_LINUX // Use kmalloc instead of OSHEAP_Alloc in Linux platform LocalData = kmalloc ((LocalDescriptorSize * NumberOfBuffers), GFP_KERNEL); #else LocalData = (char *) OSHEAP_Alloc (LocalDescriptorSize * NumberOfBuffers); #endif // UNDER_LINUX if (!LocalData) { IPC_TRACE (IPC_Channel_Error, "IPC_CreateBufferPool", "LocalData OSHEAP_Alloc Failed", 0, 0, 0, 0); return 0; } } else { LocalData = 0; } // Initialise Pool PoolPtr = IPC_PoolPtr(Pool); PoolPtr->Cpu = IPC_SM_CURRENT_CPU; PoolPtr->SourceEndpointId = SourceEndpointId; PoolPtr->DestinationEndpointId = DestinationEndpointId; PoolPtr->MaxDataSize = MaxDataSize; PoolPtr->MaxHeaderSize = DestinationEpPtr->MaxHeaderSize; PoolPtr->FlowStartLimit = FlowStartLimit; PoolPtr->FlowStopLimit = FlowStopLimit; PoolPtr->FlowControlState = IPC_FLOW_START; PoolPtr->FlowControlCallPending = IPC_FALSE; PoolPtr->FreeBuffers = NumberOfBuffers; PoolPtr->MaxBuffers = NumberOfBuffers; PoolPtr->LowWaterMark = NumberOfBuffers; PoolPtr->NextPool = 0; PoolPtr->BufferFreeFunction = NULL; PoolPtr->AllocationFailures = 0; PoolPtr->Allocations = 0; PoolPtr->BytesSent = 0; PoolPtr->FlowStopCalls = 0; PoolPtr->FlowStartCalls = 0; PoolPtr->EmptyEvent = IPC_EVENT_CREATE; IPC_QInitialise (IPC_SmOffset(&PoolPtr->FreeBufferQ), Pool); IPC_QInitialise (IPC_SmOffset(&PoolPtr->AllocatedBufferQ), Pool); // Initialise Buffers in pool Buffer = Pool + sizeof (IPC_BufferPool_T); for (Id = 0; Id < NumberOfBuffers; Id++) { IPC_BufferToPtr (Buffer)->LocalData = LocalData; LocalData += LocalDescriptorSize; IPC_QAddBack (Buffer, IPC_POOLFreeQ(Pool)); Buffer = IPC_BufferInitialise (Pool, Buffer, Id, PoolPtr->MaxHeaderSize, MaxDataSize); } // For Debug { IPC_PoolList_T * EpPools = &PoolList [PoolPtr->SourceEndpointId]; if (EpPools->Count < IPC_POOLLIST_LENGTH) { EpPools->Pool [EpPools->Count++] = PoolPtr; } } IPC_TRACE (IPC_Channel_Pool, "IPC_CreateBufferPool", "Pool %08X", Pool, 0, 0, 0); return 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; }