IPC_Boolean IPC_SmIsEndpointRegistered(IPC_EndpointId_T EndpointId) { IPC_Endpoint EndpointPtr = IPC_SmEndpointInfo(EndpointId); if (EndpointPtr == 0) return IPC_FALSE; else return IPC_TRUE; }
void IPC_SmSendBuffer(IPC_Buffer Buffer) { IPC_EndpointId_T DestinationEpId; IPC_Endpoint DestinationEpPtr; IPC_CPU_ID_T DestinationCpu; DestinationEpId = IPC_BufferDestinationEndpointId(Buffer); #ifdef IPC_DEBUG if (DestinationEpId == IPC_EP_None) { IPC_TRACE(IPC_Channel_Error, "IPC_SmSendBuffer", "Invalid Destination Endpoint %08X for Buffer %08X", DestinationEpId, Buffer, 0, 0); return; } #endif #ifdef FUSE_IPC_CRASH_SUPPORT if (g_bCpCrashed == IPC_TRUE) { IPC_TRACE(IPC_Channel_Error, "IPC_SmSendBuffer", "Trying to send after CP has crashed for Buffer %08X", Buffer, 0, 0, 0); return; } #endif DestinationEpPtr = IPC_SmEndpointInfo(DestinationEpId); DestinationCpu = DestinationEpPtr->Cpu; IPC_TRACE(IPC_Channel_Sm, "IPC_SmSendBuffer", "DestinationCpu %02X, Buffer %08X", DestinationCpu, Buffer, 0, 0); if (DestinationCpu == IPC_SM_CURRENT_CPU) { (*DestinationEpPtr->DeliveryFunction) (Buffer); } else { IPC_Fifo SendFifo = &SmLocalControl.SmControl-> Fifos[IPC_CPU_ID_INDEX(DestinationCpu)].SendFifo; IPC_SmFifoWrite(SendFifo, Buffer); } }
void IPC_ReportFlowControlEvent(IPC_BufferPool_T *PoolPtr, IPC_FlowCtrlEvent_T Event) { IPC_FlowCtrlEvent_T ReportedFlowControlState; IPC_Endpoint SourceEp = IPC_SmEndpointInfo(PoolPtr->SourceEndpointId); IPC_BufferPool Pool = IPC_SmOffset(PoolPtr); CRITICAL_REIGON_SETUP if (!SourceEp->FlowControlFunction) { /* No Flow Control callback defined */ PoolPtr->FlowControlCallPending = IPC_FALSE; return; } CRITICAL_REIGON_ENTER if (Event != PoolPtr->FlowControlState) { /* State has already changed back - do not report change */ PoolPtr->FlowControlCallPending = IPC_FALSE; CRITICAL_REIGON_LEAVE return; }
//************************************************** 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; }
void IPC_ReportFlowControlEvent(IPC_BufferPool_T *PoolPtr, IPC_FlowCtrlEvent_T Event) { IPC_FlowCtrlEvent_T ReportedFlowControlState; IPC_Endpoint SourceEp = IPC_SmEndpointInfo(PoolPtr->SourceEndpointId); IPC_BufferPool Pool = IPC_SmOffset(PoolPtr); CRITICAL_REIGON_SETUP if (!SourceEp->FlowControlFunction) { /* No Flow Control callback defined */ PoolPtr->FlowControlCallPending = IPC_FALSE; return; } CRITICAL_REIGON_ENTER(PoolPtr->Lock); if (Event != PoolPtr->FlowControlState) { /* State has already changed back - do not report change */ PoolPtr->FlowControlCallPending = IPC_FALSE; CRITICAL_REIGON_LEAVE(PoolPtr->Lock); return; } CRITICAL_REIGON_LEAVE(PoolPtr->Lock); ReportedFlowControlState = Event; while (1) { /* Update Statistics */ switch (ReportedFlowControlState) { case IPC_FLOW_START: PoolPtr->FlowStartCalls++; break; case IPC_FLOW_STOP: PoolPtr->FlowStopCalls++; break; default: /* Something badly wrong */ break; } #ifndef UNDER_LINUX if (PoolPtr->DestinationEndpointId != IPC_EP_LogApps) { IPC_TRACE(IPC_Channel_FlowControl, "IPC_ReportFlowControlEvent", "Pool %08X, Function %08X, FlowEvent %01d, ReportedEvent %01d", Pool, SourceEp->FlowControlFunction, Event, ReportedFlowControlState); } #endif #ifndef UNDER_LINUX (*SourceEp->FlowControlFunction) (Pool, ReportedFlowControlState); CRITICAL_REIGON_ENTER(PoolPtr->Lock); #else /* Linux Issue: ==> Before PoolPtr->FlowControlCallPending is set to FALSE, the cbk ( IPC_FLOW_START ) will trigger Net IRQ calling IPC_AllocateBufferWait() ==> Now the buffer count is zero but the IPC_AllocateBuffer() does not report IPC_FLOW_STOP since the PoolPtr->FlowControlCallPending is still TRUE ==> The Net IRQ calls IPC_AllocateBufferWait() again (since IPC_FLOW_STOP was not sent ) and caz of no buffer, it will try to Wait on Event ==> Waiting on event is not permitted in Net IRQ and results in crash. Solution: ==> Enter Critical region before calling cbk(IPC_FLOW_START). The critical region disables Net IRQ ==> PoolPtr->FlowControlCallPending is set to FALSE and then the Critical region exits which then triggers Net IRQ. */ CRITICAL_REIGON_ENTER(PoolPtr->Lock); (*SourceEp->FlowControlFunction) (Pool, ReportedFlowControlState); #endif if (ReportedFlowControlState == PoolPtr->FlowControlState) { PoolPtr->FlowControlCallPending = IPC_FALSE; CRITICAL_REIGON_LEAVE(PoolPtr->Lock); return; } ReportedFlowControlState = PoolPtr->FlowControlState; CRITICAL_REIGON_LEAVE(PoolPtr->Lock); } }
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)); } } } }