NvError NvEcPowerSuspend( NvEcPowerState PowerState) { NvError e = NvSuccess; NvEcPrivState *ec = &g_ec; NvOsMutexLock(ec->mutex); // Call transport's power off only if it's in ON state if (ec->powerState == NV_TRUE) { // Perform pre-suspend EC operations NV_CHECK_ERROR_CLEANUP( NvEcPrivPowerSuspendHook(ec->hEc, PowerState) ); // Enter low power state ec->EnterLowPowerState = NV_TRUE; // Signal priv thread to get ready for power suspend. NvOsSemaphoreSignal(ec->sema); // Wait till priv thread is ready for power suspend. NvOsSemaphoreWait(ec->LowPowerEntrySema); e = NvEcTransportPowerSuspend(ec->transport); ec->powerState = NV_FALSE; } fail: NvOsMutexUnlock(ec->mutex); return e; }
static void nvec_battery_remove(struct nvec_device *pdev) { unsigned int i = 0; if (batt_dev) { batt_dev->exitThread = NV_TRUE; if (batt_dev->hOdmSemaphore) { NvOsSemaphoreSignal(batt_dev->hOdmSemaphore); NvOsSemaphoreDestroy(batt_dev->hOdmSemaphore); batt_dev->hOdmSemaphore = NULL; } if (batt_dev->hBattEventThread) { NvOsThreadJoin(batt_dev->hBattEventThread); } if (batt_dev->hOdmBattDev) { device_remove_file(&pdev->dev, &tegra_battery_attr); device_remove_file(&pdev->dev, &tegra_battery_version); //Daniel 20100823, put ec version to fs del_timer_sync(&(batt_dev->battery_poll_timer)); NvOdmBatteryDeviceClose(batt_dev->hOdmBattDev); batt_dev->hOdmBattDev = NULL; for (i = 0; i < ARRAY_SIZE(tegra_power_supplies); i++) { power_supply_unregister(&tegra_power_supplies[i]); } } kfree(batt_dev); batt_dev = NULL; } }
NvError NvEcPowerResume(void) { NvError e = NvSuccess; NvEcPrivState *ec = &g_ec; NvOsMutexLock(ec->mutex); // Call transport's power on if it's OFF state if (ec->powerState == NV_FALSE) { NvOsDebugPrintf("ec_rs NvEcPowerResume 1\n"); NV_CHECK_ERROR_CLEANUP( NvEcTransportPowerResume(ec->transport) ); ec->powerState = NV_TRUE; ec->EnterLowPowerState = NV_FALSE; // Signal priv thread to get out of power suspend. NvOsSemaphoreSignal(ec->LowPowerExitSema); // Perform post-resume EC operations NvEcPrivPowerResumeHook(ec->hEc); NvOsDebugPrintf("ec_rs NvEcPowerResume 2\n"); } fail: NvOsMutexUnlock(ec->mutex); return e; }
/* Process receive response and update individual timeout */ static NvError NvEcPrivProcessReceiveResponse( NvEcPrivState *ec, NvError transportStatus ) { NvError e = NvSuccess; NvEcResponse packet; NvEcResponseNode *responseNode = NULL; NvU32 size; // FIXME: remove this extra copying and buffering for optimization NV_CHECK_ERROR( NvEcTransportGetReceivePacket( ec->transport, &packet, sizeof(NvEcResponse) ) ); // nothing we can do here if error! NvEcPrivFindAndDequeueResponse( ec, &packet, &responseNode); if ( responseNode ) { size = responseNode->size; if ( size > sizeof(NvEcResponse) ) size = sizeof(NvEcResponse); NvOsMemcpy( &responseNode->response, &packet, size ); responseNode->status = transportStatus; NvOsSemaphoreSignal(responseNode->sema); // all response stuff should be completed before signalling } else e = NvError_BadParameter; // will return Bad Param if can't find waiting response return e; }
void tegra_audiofx_destroyfx(struct tegra_audio_data *audio_context) { FxNotifier *m_FxNotifier = (FxNotifier*)&audio_context->m_FxNotifier; if (m_FxNotifier->Connected) { m_FxNotifier->Exit = 1; NvOsSemaphoreSignal(m_FxNotifier->hTransportSemaphore); NvOsThreadJoin(m_FxNotifier->hTransportThread); m_FxNotifier->hTransportThread = 0; tegra_transport_set_property( (NvAudioFxObjectHandle)m_FxNotifier->hNotifier, NvAudioFxNotifierProperty_Disconnect, 0, 0); } if (m_FxNotifier->hTransport) { NvRmTransportClose(m_FxNotifier->hTransport); m_FxNotifier->hTransport = 0; } if (m_FxNotifier->hNotifier) { tegra_transport_mixer_destroy_object( (NvAudioFxObjectHandle)m_FxNotifier->hNotifier); m_FxNotifier->hNotifier = 0; } if (m_FxNotifier->hTransportSemaphore) { NvOsSemaphoreDestroy(m_FxNotifier->hTransportSemaphore); m_FxNotifier->hTransportSemaphore = 0; } return; }
void NvEcPrivProcessSendRequest( NvEcPrivState *ec ) { NvEcRequestNode *requestNode; NvOsMutexLock( ec->requestMutex ); if ( ec->requestBegin ) { DISP_MESSAGE(("\r\nProcessSendReq requestBegin=0x%x", ec->requestBegin)); requestNode = ec->requestBegin; // Update timeouts requestNode->timeout = NVEC_REQUEST_TIMEOUT_DEFAULT; ec->timeout[NVEC_IDX_REQUEST] = requestNode->timeout; ec->timeoutBase[NVEC_IDX_REQUEST] = ec->lastTime; DISP_MESSAGE(("\r\nec->timeout[NVEC_IDX_REQUEST] is set to=%d", ec->timeout[NVEC_IDX_REQUEST])); if ( NvSuccess != NvEcTransportAsyncSendPacket( ec->transport, &requestNode->request, requestNode->size ) ) { // transport send fail: de-queue, set status and signal ec->requestBegin = requestNode->next; if ( NULL == ec->requestBegin ) ec->requestEnd = NULL; requestNode->status = NvError_I2cWriteFailed; DISP_MESSAGE(("\r\nProcessSendReq Async Send failed")); DISP_MESSAGE(("\r\nProcessSendReq requestBegin=0x%x", ec->requestBegin)); NvOsSemaphoreSignal( requestNode->sema ); } } NvOsMutexUnlock( ec->requestMutex ); }
/* We could potentially re-adjust the internal eventNode queue when there is no ready queue to base on accumulated NumEventPacket hint. */ NvError NvEcGetEvent( NvEcEventRegistrationHandle hEcEventRegistration, NvEcEvent *pEvent, NvU32 EventSize) { NvEcHandle hEc = hEcEventRegistration->hEc; NvEcPrivState *ec = hEc->ec; NvError e = NvError_InvalidState; NvEcEventNode *eventNode, *t; NvU32 tagMask = (1UL << hEc->tag); // FIXME: Should change these to assert ??? if ( !pEvent ) return NvError_InvalidAddress; if ( !hEcEventRegistration ) return NvError_BadParameter; if ( EventSize > sizeof(NvEcEvent) ) EventSize = sizeof(NvEcEvent); else if ( EventSize < NVEC_MIN_EVENT_SIZE ) return NvError_InvalidSize; NvOsMutexLock( ec->eventMutex ); eventNode = ec->eventReadyBegin; while ( eventNode ) { // pre advance eventNode since current one could be removed t = eventNode; eventNode = eventNode->next; if ( (hEcEventRegistration->eventBitmap & (1UL << t->event.EventType)) && (t->tagBitmap & tagMask) ) { // only return event with matching client tag set NvOsMemcpy( pEvent, &(t->event), EventSize ); e = NvSuccess; t->tagBitmap &= ~tagMask; // removed if all registered client has GetEvent(t) if ( !t->tagBitmap ) { // In case transport has been nack'ing due to eventFree // queue is all used up, signal thread to retrieve // queued up event in transport. eventMutex should // synchronize NvEcPrivProcessReceiveEvent properly. if ( NULL == ec->eventFreeBegin ) NvOsSemaphoreSignal( ec->sema ); NvEcPrivRemoveEventFromReady( ec, t ); } break; } } NvOsMutexUnlock( ec->eventMutex ); return e; }
/* * Since send request is blocking, only need to check requestBegin: * - returns the requestBegin if asked * - check if requestBegin timeout (will signal back too) * - Update requestBegin's timeout by rebasing to * EcPrivThread-global time (hEc->lastTime). * - reset queue timeout to NV_WAIT_INFINITE */ static void NvEcPrivFindAndDequeueRequest( NvEcPrivState *ec, NvEcRequestNode **pRequestNode, NvError transportStatus, NvBool skipTimeout ) { NvEcRequestNode *t = NULL; NvBool remove = skipTimeout; // always remove node with success if skipTimeout NvOsMutexLock( ec->requestMutex ); NV_ASSERT(ec->requestBegin); t = ec->requestBegin; DISP_MESSAGE(("\r\nFindDQReq requestBegin=0x%x", ec->requestBegin)); if ( t ) { if ( pRequestNode ) *pRequestNode = t; if ( skipTimeout ) t->status = transportStatus; else if ( t->timeout <= NVEC_TIMEDIFF_WITH_BASE(ec, NVEC_IDX_REQUEST) ) { NvEcTransportAbortSendPacket( ec->transport, &t->request, t->size ); t->status = NvError_Timeout; remove = NV_TRUE; DISP_MESSAGE(("RQ time out Reqnode=0x%x", t)); } if ( remove ) { ec->requestBegin = t->next; if ( NULL == ec->requestBegin ) ec->requestEnd = NULL; DISP_MESSAGE(("\r\nFindDQReq removed=0x%x, removed->next=0x%x, " "ec->requestBegin=0x%x, t->status=0x%x", t, t->next, ec->requestBegin, t->status)); if ( pRequestNode == NULL ) NvOsSemaphoreSignal( t->sema ); } else { t->timeout -= NVEC_TIMEDIFF_WITH_BASE(ec, NVEC_IDX_REQUEST); // update this request timeout with lastTime base } // update with per-queue timeout and timeoutBase ec->timeout[NVEC_IDX_REQUEST] = NV_WAIT_INFINITE; ec->timeoutBase[NVEC_IDX_REQUEST] = ec->lastTime; DISP_MESSAGE(("\r\nec->timeout[NVEC_IDX_REQUEST] is set to=%d", ec->timeout[NVEC_IDX_REQUEST])); } NvOsMutexUnlock( ec->requestMutex ); }
static void PowerEventNotify( NvRmDeviceHandle hRmDeviceHandle, NvRmPowerEvent Event) { NvU32 i; NvRmPowerClient* pPowerClient = NULL; NvRmPowerRegistry* pRegistry = &s_PowerRegistry; NVRM_POWER_PRINTF(("%s is reported to RM clients\n", (Event == NvRmPowerEvent_WakeLP0)? "Wake from LP0" : "Wake from LP1")); // Restore clocks after LP0 if (Event == NvRmPowerEvent_WakeLP0) NvRmPrivClocksResume(hRmDeviceHandle); // Store event for all registered clients, and signal only those, that // have provided valid semaphore handle; on wake from low power states // set power cycled indicators for (i = 0; i < pRegistry->UsedIndexRange; i++) { pPowerClient = pRegistry->pPowerClients[i]; if (pPowerClient != NULL) { ModuleVoltageReq* pVoltageReq = pPowerClient->pVoltageReqHead; while (pVoltageReq != NULL) { if (Event == NvRmPowerEvent_WakeLP0) { //LP0: all power groups, except AO group, are powered down // when core power is down if (pVoltageReq->PowerGroup != NV_POWERGROUP_AO) pVoltageReq->PowerCycled = NV_TRUE; } else if (Event == NvRmPowerEvent_WakeLP1) { // LP1: core power is preserved; but all power groups // except AO and NPG group are power gated if ((pVoltageReq->PowerGroup != NV_POWERGROUP_AO) && (pVoltageReq->PowerGroup != NV_POWERGROUP_NPG)) pVoltageReq->PowerCycled = NV_TRUE; } pVoltageReq = pVoltageReq->pNext; } pPowerClient->Event = Event; if (pPowerClient->hEventSemaphore != NULL) { NvOsSemaphoreSignal(pPowerClient->hEventSemaphore); } } } }
static ssize_t tegra_battery_store_property( struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { unsigned int value = 0; value = simple_strtoul(buf, NULL, 0); NvOsMutexLock(batt_dev->hBattEventMutex); batt_dev->batt_status_poll_period = value; NvOsMutexUnlock(batt_dev->hBattEventMutex); NvOsSemaphoreSignal(batt_dev->hOdmSemaphore); return count; }
static void PmuThreadTerminate(NvRmPmu* pPmu) { /* * Request thread abort, signal semaphore to make sure the thread is * awaken and wait for its self-termination. Do nothing if invalid PMU * structure */ if (pPmu) { if (pPmu->hSemaphore && pPmu->hThread) { pPmu->AbortThread = NV_TRUE; NvOsSemaphoreSignal(pPmu->hSemaphore); NvOsThreadJoin(pPmu->hThread); } pPmu->AbortThread = NV_FALSE; } }
static void NvEcPrivProcessPostSendRequest( NvEcPrivState *ec, NvError transportStatus ) { NvEcRequestNode *requestNode = NULL; NvEcResponseNode *responseNode; NvEcPrivFindAndDequeueRequest(ec, &requestNode, transportStatus, NV_TRUE); // update corresponding responseNode timeout if ( requestNode ) { requestNode->completed = NV_TRUE; responseNode = requestNode->responseNode; if ( responseNode ) { NvOsMutexLock( ec->responseMutex ); NV_ASSERT(ec->responseBegin); if ( NV_WAIT_INFINITE == ec->timeout[NVEC_IDX_RESPONSE] ) { // no current pending response on timeout watch. // Update response queue timeout. responseNode->timeout = NVEC_RESPONSE_TIMEOUT_DEFAULT; ec->timeout[NVEC_IDX_RESPONSE] = responseNode->timeout; ec->timeoutBase[NVEC_IDX_RESPONSE] = ec->lastTime; DISP_MESSAGE(("\r\nec->timeout[NVEC_IDX_RESPONSE] is set to=%d", ec->timeout[NVEC_IDX_RESPONSE])); } else { // Update this response timeout with current lastTime as base responseNode->timeout = NVEC_RESPONSE_TIMEOUT_DEFAULT + NVEC_TIME_BASE(ec, NVEC_IDX_RESPONSE); // wraparound time difference will work too. } NvOsMutexUnlock( ec->responseMutex ); } NvOsSemaphoreSignal( requestNode->sema ); // all request stuff should be done before signal } }
void tegra_transport_deinit(void) { if (!atrans) goto EXIT; spin_lock(&atrans->lock); atrans->RefCount--; if (atrans->RefCount > 0){ spin_unlock(&atrans->lock); goto EXIT; } spin_unlock(&atrans->lock); atrans->ShutDown = 1; if (atrans->hRmTransport) { NvRmTransportClose(atrans->hRmTransport); atrans->hRmTransport = 0; atrans->TransportConnected = 0; } if (atrans->hServiceThread) { NvOsSemaphoreSignal(atrans->hServiceSema); NvOsThreadJoin(atrans->hServiceThread); atrans->hServiceThread = 0; } if (atrans->hServiceSema) { NvOsSemaphoreDestroy(atrans->hServiceSema); atrans->hServiceSema = 0; } atrans->hRmDevice = 0; kfree(atrans); atrans = 0; EXIT: return; }
static void nvec_battery_remove(struct nvec_device *pdev) { unsigned int i = 0; if (batt_dev) { batt_dev->exitThread = NV_TRUE; if (batt_dev->hOdmSemaphore) { NvOsSemaphoreSignal(batt_dev->hOdmSemaphore); NvOsSemaphoreDestroy(batt_dev->hOdmSemaphore); batt_dev->hOdmSemaphore = NULL; } if (batt_dev->hBattEventThread) { NvOsThreadJoin(batt_dev->hBattEventThread); } if (batt_dev->hBattEventMutex) { NvOsMutexDestroy(batt_dev->hBattEventMutex); batt_dev->hBattEventMutex = NULL; } if (batt_dev->hOdmBattDev) { device_remove_file(&pdev->dev, &tegra_battery_attr); NvOdmBatteryDeviceClose(batt_dev->hOdmBattDev); batt_dev->hOdmBattDev = NULL; for (i = 0; i < ARRAY_SIZE(tegra_power_supplies); i++) { power_supply_unregister(&tegra_power_supplies[i]); } } kfree(batt_dev); batt_dev = NULL; } }
void NvOdmOsSemaphoreSignal(NvOdmOsSemaphoreHandle semaphore) { NvOsSemaphoreSignal( (NvOsSemaphoreHandle)semaphore ); }
static int nvec_battery_probe(struct nvec_device *pdev) { int i, rc; NvError ErrorStatus = NvSuccess; NvBool result = NV_FALSE; batt_dev = kzalloc(sizeof(struct tegra_battery_dev), GFP_KERNEL); if (!batt_dev) { pr_err("nvec_battery_probe:NOMEM\n"); return -ENOMEM; } ErrorStatus = NvOsSemaphoreCreate(&batt_dev->hOdmSemaphore, 0); if (NvSuccess != ErrorStatus) { pr_err("NvOsSemaphoreCreate Failed!\n"); goto Cleanup; } batt_dev->exitThread = NV_FALSE; ErrorStatus = NvOsThreadCreate(NvBatteryEventHandlerThread, batt_dev, &(batt_dev->hBattEventThread)); if (NvSuccess != ErrorStatus) { pr_err("NvOsThreadCreate FAILED\n"); goto Cleanup; } result = NvOdmBatteryDeviceOpen(&(batt_dev->hOdmBattDev), (NvOdmOsSemaphoreHandle *)&batt_dev->hOdmSemaphore, &(batt_dev->ec_version)); //Daniel 20100823, put ec version to fs. if (!result || !batt_dev->hOdmBattDev) { pr_err("NvOdmBatteryDeviceOpen FAILED\n"); goto Cleanup; } for (i = 0; i < ARRAY_SIZE(tegra_power_supplies); i++) { if (power_supply_register(&pdev->dev, &tegra_power_supplies[i])) pr_err("Failed to register power supply\n"); } batt_dev->batt_status_poll_period = NVBATTERY_POLLING_INTERVAL_MILLISECS; setup_timer(&(batt_dev->battery_poll_timer), tegra_battery_poll_timer_func, 0); mod_timer(&(batt_dev->battery_poll_timer), jiffies + msecs_to_jiffies(batt_dev->batt_status_poll_period)); rc = device_create_file(&pdev->dev, &tegra_battery_attr); rc = device_create_file(&pdev->dev, &tegra_battery_version); //Daniel 20100823, put ec version to fs if (rc) { for (i = 0; i < ARRAY_SIZE(tegra_power_supplies); i++) { power_supply_unregister(&tegra_power_supplies[i]); } del_timer_sync(&(batt_dev->battery_poll_timer)); pr_err("nvec_battery_probe:device_create_file FAILED"); goto Cleanup; } return 0; Cleanup: batt_dev->exitThread = NV_TRUE; if (batt_dev->hOdmSemaphore) { NvOsSemaphoreSignal(batt_dev->hOdmSemaphore); NvOsSemaphoreDestroy(batt_dev->hOdmSemaphore); batt_dev->hOdmSemaphore = NULL; } if (batt_dev->hBattEventThread) { NvOsThreadJoin(batt_dev->hBattEventThread); } if (batt_dev->hOdmBattDev) { NvOdmBatteryDeviceClose(batt_dev->hOdmBattDev); batt_dev->hOdmBattDev = NULL; } kfree(batt_dev); batt_dev = NULL; return -1; }
void NvEcClose(NvEcHandle hEc) { NvEcPrivState *ec; NvBool destroy = NV_FALSE; if ( NULL == hEc ) return; NV_ASSERT( s_refcount ); ec = hEc->ec; NvOsMutexLock( ec->mutex ); // FIXME: handle client still with outstanding event types if ( !--s_refcount ) { NvEcPrivDeinitHook(ec->hEc); NV_ASSERT( NULL == ec->eventReg[hEc->tag].regBegin && NULL == ec->eventReg[hEc->tag].regEnd ); NV_ASSERT( NULL == ec->requestBegin && NULL == ec->requestEnd ); NV_ASSERT( NULL == ec->responseBegin && NULL == ec->responseEnd ); #ifndef CONFIG_TEGRA_ODM_BETELGEUSE ec->exitPingThread = NV_TRUE; NvOsSemaphoreSignal( ec->hPingSema ); NvOsThreadJoin( ec->hPingThread ); #endif ec->exitThread = NV_TRUE; NvOsSemaphoreSignal( ec->sema ); NvOsThreadJoin( ec->thread ); NvEcTransportClose( ec->transport ); NvOsMutexDestroy( ec->requestMutex ); NvOsMutexDestroy( ec->responseMutex ); NvOsMutexDestroy( ec->eventMutex ); NvOsSemaphoreDestroy( ec->sema ); #ifndef CONFIG_TEGRA_ODM_BETELGEUSE NvOsSemaphoreDestroy( ec->hPingSema ); #endif NvOsSemaphoreDestroy( ec->LowPowerEntrySema ); NvOsSemaphoreDestroy( ec->LowPowerExitSema ); destroy = NV_TRUE; NvOsFree( ec->eventNodes ); NvOsFree( ec->hEc ); } // Set this flag as FALSE to indicate power is disabled //Daniel 20100723, if we change power state to NV_FALSE, we won't be able to suspend/poweroff it. //Is there any side effect ????? //ec->powerState = NV_FALSE; NV_ASSERT( hEc->tag < NVEC_MAX_REQUESTOR_TAG ); ec->tagAllocated[hEc->tag] = NV_FALSE; // to be recycled NvOsFree( hEc ); NvOsMutexUnlock( ec->mutex ); if ( destroy ) { NvOsMutexDestroy( ec->mutex ); NvOsMemset( ec, 0, sizeof(NvEcPrivState) ); ec->mutex = NULL; } }
/* * Process receive (response & event) and update individual timeout. * * Return NvError_InsufficientMemory due to 2 conditions: * - internal event queue (ec->eventNodes) too small. * - client did NvEcRegisterForEvents. * Skip TransportGetReceivePacket and transport will keep NACK'ing EC in this * error case. */ static NvError NvEcPrivProcessReceiveEvent( NvEcPrivState *ec, NvError transportStatus ) { NvError e = NvSuccess; NvEcEventNode *eventNode = NULL; NvEcEventRegistration *reg = NULL; NvEcEvent *packet = NULL; NvEcEventType eventType; NvU32 i, tagBitmap; NvOsMutexLock( ec->eventMutex ); if ( ec->eventFreeBegin ) { eventNode = ec->eventFreeBegin; packet = &eventNode->event; } else { e = NvError_InsufficientMemory; goto fail; } NV_CHECK_ERROR( NvEcTransportGetReceivePacket( ec->transport, (NvEcResponse *)packet, sizeof(NvEcEvent) ) ); // nothing we can do here if error! eventType = packet->EventType; NV_ASSERT( eventType < NvEcEventType_Num ); e = NvError_InvalidState; // init to event type never registered i = 0; tagBitmap = ec->eventTagBitmap[eventType]; while( tagBitmap ) { NV_ASSERT( i < NvEcEventType_Num ); if ( tagBitmap & 1 ) { reg = ec->eventMap[i][eventType]; NV_ASSERT( reg ); if ( NvSuccess != e ) { // dequeue from free and enqueue into ready if not done yet ec->eventFreeBegin = eventNode->next; if ( ec->eventFreeBegin == NULL ) ec->eventFreeEnd = NULL; eventNode->timeout = NVEC_EVENT_TIMEOUT_DEFAULT; // ??? eventNode->tagBitmap = ec->eventTagBitmap[eventType]; eventNode->next = NULL; NVEC_ENQ( ec->eventReady, eventNode ); e = NvSuccess; } NvOsSemaphoreSignal( reg->sema ); } i++; tagBitmap = tagBitmap >> 1; } fail: NvOsMutexUnlock( ec->eventMutex ); return e; }
static void PmuIsr(void* args) { NvRmPmu* pPmu = (NvRmPmu*)args; NvOsSemaphoreSignal(pPmu->hSemaphore); }
/* * Traverse response nodes with these: * - one response matching the tag param (returns the node). If bypassing * tag checking, use INVALID tag as parameter. * - all responses timeout (will signal back too) * - Update individual responseNode's timeout by rebasing to * EcPrivThread-global time (hEc->lastTime). * - Update shortest timeout value for response queue. */ static void NvEcPrivFindAndDequeueResponse( NvEcPrivState *ec, NvEcResponse *response, NvEcResponseNode **pResponseNode ) { NvEcResponseNode *t = NULL, *p = NULL, *temp; NvU32 timeout = NV_WAIT_INFINITE; NvBool remove = NV_FALSE, found = NV_FALSE; NvBool SignalSema; NvOsMutexLock( ec->responseMutex ); NV_ASSERT(ec->responseBegin); DISP_MESSAGE(("\r\nFindDQRes responseBegin=0x%x", ec->responseBegin)); if ( ec->responseBegin ) { t = ec->responseBegin; while( t ) { SignalSema = NV_FALSE; /* FIXME: just match tag? more to match? * There may be the cases where spurious response is received from EC. * Response should not be removed from the queue until req is complete. */ DISP_MESSAGE(("t->tag=0x%x\n", t->tag)); if (response) DISP_MESSAGE(("response->RequestorTag=0x%x\n", response->RequestorTag)); if ( response && !found && (t->tag == response->RequestorTag) && t->requestNode->completed ) { if ( pResponseNode ) *pResponseNode = t; found = NV_TRUE; remove = NV_TRUE; } else { #if ENABLE_TIMEOUT if ( t->timeout <= NVEC_TIMEDIFF_WITH_BASE(ec, NVEC_IDX_RESPONSE) ) { t->status = NvError_Timeout; SignalSema = NV_TRUE; remove = NV_TRUE; DISP_MESSAGE(("Resp Timeout Respnode=0x%x", t)); } else { // This check is needed for spurious response case handling. if (t->timeout != NV_WAIT_INFINITE) t->timeout -= NVEC_TIMEDIFF_WITH_BASE(ec, NVEC_IDX_RESPONSE); // update this response timeout w/ lastTime as base } #endif } if ( remove ) { temp = t; NVEC_UNLINK( ec->response, t, p ); DISP_MESSAGE(("\r\nFindDQRes removed=0x%x, removed->next=0x%x, " "prev=0x%x ec->responseBegin=0x%x", t, t->next, p, ec->responseBegin)); remove = NV_FALSE; if (p) t = p->next; else t = ec->responseBegin; if (SignalSema == NV_TRUE) NvOsSemaphoreSignal( temp->sema ); } else { if ( timeout > t->timeout ) timeout = t->timeout; p = t; t = t->next; } } // update with per-queue timeout and timeoutBase ec->timeout[NVEC_IDX_RESPONSE] = timeout; ec->timeoutBase[NVEC_IDX_RESPONSE] = ec->lastTime; DISP_MESSAGE(("\r\nec->timeout[NVEC_IDX_RESPONSE] is set to=%d", ec->timeout[NVEC_IDX_RESPONSE])); } if (found == NV_FALSE) NvOsDebugPrintf("\r\n***NVEC:Received Spurious Response from EC."); NvOsMutexUnlock( ec->responseMutex ); }
void NvEcClose(NvEcHandle hEc) { NvEcPrivState *ec; NvBool destroy = NV_FALSE; if ( NULL == hEc ) return; NV_ASSERT( s_refcount ); ec = hEc->ec; NvOsMutexLock( ec->mutex ); // FIXME: handle client still with outstanding event types if ( !--s_refcount ) { NvEcPrivDeinitHook(ec->hEc); NV_ASSERT( NULL == ec->eventReg[hEc->tag].regBegin && NULL == ec->eventReg[hEc->tag].regEnd ); NV_ASSERT( NULL == ec->requestBegin && NULL == ec->requestEnd ); NV_ASSERT( NULL == ec->responseBegin && NULL == ec->responseEnd ); ec->exitPingThread = NV_TRUE; NvOsSemaphoreSignal( ec->hPingSema ); NvOsThreadJoin( ec->hPingThread ); ec->exitThread = NV_TRUE; NvOsSemaphoreSignal( ec->sema ); NvOsThreadJoin( ec->thread ); NvEcTransportClose( ec->transport ); NvOsMutexDestroy( ec->requestMutex ); NvOsMutexDestroy( ec->responseMutex ); NvOsMutexDestroy( ec->eventMutex ); NvOsSemaphoreDestroy( ec->sema ); NvOsSemaphoreDestroy( ec->hPingSema ); NvOsSemaphoreDestroy( ec->LowPowerEntrySema ); NvOsSemaphoreDestroy( ec->LowPowerExitSema ); destroy = NV_TRUE; NvOsFree( ec->eventNodes ); NvOsFree( ec->hEc ); } // Set this flag as FALSE to indicate power is disabled ec->powerState = NV_FALSE; NV_ASSERT( hEc->tag < NVEC_MAX_REQUESTOR_TAG ); ec->tagAllocated[hEc->tag] = NV_FALSE; // to be recycled NvOsFree( hEc ); NvOsMutexUnlock( ec->mutex ); if ( destroy ) { NvOsMutexDestroy( ec->mutex ); NvOsMemset( ec, 0, sizeof(NvEcPrivState) ); ec->mutex = NULL; } }
NvError NvEcOpen(NvEcHandle *phEc, NvU32 InstanceId) { NvEc *hEc = NULL; NvU32 i; NvEcPrivState *ec = &g_ec; NvOsMutexHandle mutex = NULL; NvError e = NvSuccess; NV_ASSERT( phEc ); if ( NULL == ec->mutex ) { e = NvOsMutexCreate(&mutex); if (NvSuccess != e) return e; if (0 != NvOsAtomicCompareExchange32((NvS32*)&ec->mutex, 0, (NvS32)mutex) ) NvOsMutexDestroy( mutex ); } NvOsMutexLock(ec->mutex); if ( !s_refcount ) { mutex = ec->mutex; NvOsMemset( ec, 0, sizeof(NvEcPrivState) ); ec->mutex = mutex; NV_CHECK_ERROR_CLEANUP( NvOsMutexCreate( &ec->requestMutex )); NV_CHECK_ERROR_CLEANUP( NvOsMutexCreate( &ec->responseMutex )); NV_CHECK_ERROR_CLEANUP( NvOsMutexCreate( &ec->eventMutex )); NV_CHECK_ERROR_CLEANUP( NvOsSemaphoreCreate( &ec->sema, 0)); NV_CHECK_ERROR_CLEANUP( NvOsSemaphoreCreate( &ec->LowPowerEntrySema, 0)); NV_CHECK_ERROR_CLEANUP( NvOsSemaphoreCreate( &ec->LowPowerExitSema, 0)); NV_CHECK_ERROR_CLEANUP( NvEcTransportOpen( &ec->transport, InstanceId, ec->sema, 0 ) ); } // Set this flag as TRUE to indicate power is enabled ec->powerState = NV_TRUE; // create private handle for internal communications between NvEc driver // and EC if ( !s_refcount ) { ec->hEc = NvOsAlloc( sizeof(NvEc) ); if ( NULL == ec->hEc ) goto clean; // reserve the zero tag for internal use by the nvec driver; this ensures // that the driver always has a requestor tag available and can therefore // always talk to the EC ec->tagAllocated[0] = NV_TRUE; ec->hEc->ec = ec; ec->hEc->tag = 0; NV_CHECK_ERROR_CLEANUP(NvOsSemaphoreCreate(&ec->hPingSema, 0)); // perform startup operations before mutex is unlocked NV_CHECK_ERROR_CLEANUP( NvEcPrivInitHook(ec->hEc) ); // start thread to send "pings" - no-op commands to keep EC "alive" NV_CHECK_ERROR_CLEANUP(NvOsThreadCreate( (NvOsThreadFunction)NvEcPrivPingThread, ec, &ec->hPingThread)); } hEc = NvOsAlloc( sizeof(NvEc) ); if ( NULL == hEc ) goto clean; NvOsMemset(hEc, 0x00, sizeof(NvEc)); hEc->ec = ec; hEc->tag = NVEC_REQUESTOR_TAG_INVALID; for ( i = 0; i < NVEC_MAX_REQUESTOR_TAG; i++ ) { if ( !ec->tagAllocated[i] ) { ec->tagAllocated[i] = NV_TRUE; hEc->tag = i; break; } } if ( NVEC_REQUESTOR_TAG_INVALID == hEc->tag ) goto clean; // run out of tag, clean it up! *phEc = hEc; s_refcount++; NvOsMutexUnlock( ec->mutex ); ec->IsEcActive = NV_FALSE; return NvSuccess; clean: NvOsFree( hEc ); NvOsMutexUnlock( ec->mutex ); return NvError_InsufficientMemory; fail: if (!s_refcount) { ec->exitPingThread = NV_TRUE; if (ec->hPingSema) NvOsSemaphoreSignal( ec->hPingSema ); NvOsThreadJoin( ec->hPingThread ); NvOsSemaphoreDestroy(ec->hPingSema); ec->exitThread = NV_TRUE; if (ec->sema) NvOsSemaphoreSignal( ec->sema ); NvOsThreadJoin( ec->thread ); NvOsFree( ec->hEc ); if ( ec->transport ) NvEcTransportClose( ec->transport ); NvOsMutexDestroy( ec->requestMutex ); NvOsMutexDestroy( ec->responseMutex ); NvOsMutexDestroy( ec->eventMutex ); NvOsSemaphoreDestroy( ec->sema ); NvOsSemaphoreDestroy( ec->LowPowerEntrySema ); NvOsSemaphoreDestroy( ec->LowPowerExitSema ); if ( ec->mutex ) { NvOsMutexUnlock( ec->mutex ); // Destroying of this mutex here is not safe, if another thread is // waiting on this mutex, it can cause issues. We shold have // serialized Init/DeInit calls for creating and destroying this mutex. NvOsMutexDestroy( ec->mutex ); NvOsMemset( ec, 0, sizeof(NvEcPrivState) ); ec->mutex = NULL; } } return NvError_NotInitialized; }
static int nvec_battery_probe(struct nvec_device *pdev) { int i, rc; NvError ErrorStatus = NvSuccess; NvBool result = NV_FALSE; batt_dev = kzalloc(sizeof(struct tegra_battery_dev), GFP_KERNEL); if (!batt_dev) { pr_err("nvec_battery_probe:NOMEM\n"); return -ENOMEM; } ErrorStatus = NvOsMutexCreate(&batt_dev->hBattEventMutex); if (NvSuccess != ErrorStatus) { pr_err("NvOsMutexCreate Failed!\n"); goto Cleanup; } ErrorStatus = NvOsSemaphoreCreate(&batt_dev->hOdmSemaphore, 0); if (NvSuccess != ErrorStatus) { pr_err("NvOsSemaphoreCreate Failed!\n"); goto Cleanup; } /*Henry++ adjust thread to be createn at last batt_dev->exitThread = NV_FALSE; batt_dev->inSuspend = NV_FALSE; ErrorStatus = NvOsThreadCreate(NvBatteryEventHandlerThread, batt_dev, &(batt_dev->hBattEventThread)); if (NvSuccess != ErrorStatus) { pr_err("NvOsThreadCreate FAILED\n"); goto Cleanup; } */ //Henry add retry when fail **** for(i=0;i<BATTERY_RETRY_TIMES;i++){ result = NvOdmBatteryDeviceOpen(&(batt_dev->hOdmBattDev), (NvOdmOsSemaphoreHandle *)&batt_dev->hOdmSemaphore); if (!result || !batt_dev->hOdmBattDev) { pr_err("NvOdmBatteryDeviceOpen FAILED,retry i=%i\n",i); NvOsWaitUS(10000); continue; } else{ break; } } if(i==BATTERY_RETRY_TIMES){ pr_err("NvOdmBatteryDeviceOpen FAILED\n"); goto Cleanup; } //****************************** for (i = 0; i < ARRAY_SIZE(tegra_power_supplies); i++) { if (power_supply_register(&pdev->dev, &tegra_power_supplies[i])) pr_err("Failed to register power supply\n"); } batt_dev->batt_status_poll_period = NVBATTERY_POLLING_INTERVAL; rc = device_create_file(&pdev->dev, &tegra_battery_attr); if (rc) { for (i = 0; i < ARRAY_SIZE(tegra_power_supplies); i++) { power_supply_unregister(&tegra_power_supplies[i]); } pr_err("nvec_battery_probe:device_create_file FAILED"); goto Cleanup; } //Henry++ adjust thread to be createn at last batt_dev->exitThread = NV_FALSE; batt_dev->inSuspend = NV_FALSE; ErrorStatus = NvOsThreadCreate(NvBatteryEventHandlerThread, batt_dev, &(batt_dev->hBattEventThread)); if (NvSuccess != ErrorStatus) { pr_err("NvOsThreadCreate FAILED\n"); goto Cleanup; } return 0; Cleanup: batt_dev->exitThread = NV_TRUE; if (batt_dev->hOdmSemaphore) { NvOsSemaphoreSignal(batt_dev->hOdmSemaphore); NvOsSemaphoreDestroy(batt_dev->hOdmSemaphore); batt_dev->hOdmSemaphore = NULL; } if (batt_dev->hBattEventThread) { NvOsThreadJoin(batt_dev->hBattEventThread); } if (batt_dev->hBattEventMutex) { NvOsMutexDestroy(batt_dev->hBattEventMutex); batt_dev->hBattEventMutex = NULL; } if (batt_dev->hOdmBattDev) { NvOdmBatteryDeviceClose(batt_dev->hOdmBattDev); batt_dev->hOdmBattDev = NULL; } kfree(batt_dev); batt_dev = NULL; //return -1; return 0; //henry++ workaround system can't enter suspend }
/* * Always use one EcPrivThread-global clock/time for timeout calculations */ static void NvEcPrivThread( void * args ) { NvEcPrivState *ec = (NvEcPrivState *)args; NvU32 t, timeout = NV_WAIT_INFINITE; NvU32 tStatus = 0; NvError wait = NvSuccess; NvError e; while( !ec->exitThread ) { #if ENABLE_TIMEOUT if ( timeout ) wait = NvOsSemaphoreWaitTimeout( ec->sema, timeout ); #else NvOsSemaphoreWait( ec->sema ); wait = NvSuccess; #endif #if ENABLE_FAKE_TIMEOUT_TEST t = ec->lastTime + 0x200; #else t = NvOsGetTimeMS(); #endif ec->timeDiff = t - ec->lastTime; ec->lastTime = t; // update last timer value if ( !timeout || (wait == NvError_Timeout) ) { // timeout case NvEcPrivProcessTimeout( ec ); } // look for any pending packets tStatus = NvEcTransportQueryStatus( ec->transport ); e = NvSuccess; /* * SEND_COMPLETE event must be processed before RESPONSE_RECEIVE_COMPLETE * event as SEND_COMPLETE event schedules timeout for RESPONSE_RECEIVE event. */ if ( tStatus & (NVEC_TRANSPORT_STATUS_SEND_COMPLETE | NVEC_TRANSPORT_STATUS_SEND_ERROR) ) { NvEcPrivProcessPostSendRequest( ec, (tStatus & NVEC_TRANSPORT_STATUS_SEND_COMPLETE) ? NvSuccess : NvError_I2cWriteFailed ); } if ( tStatus & (NVEC_TRANSPORT_STATUS_RESPONSE_RECEIVE_ERROR | NVEC_TRANSPORT_STATUS_RESPONSE_RECEIVE_COMPLETE) ) { e = (tStatus & NVEC_TRANSPORT_STATUS_RESPONSE_RECEIVE_COMPLETE) ? NvSuccess : NvError_I2cReadFailed; e = NvEcPrivProcessReceiveResponse( ec, e ); // return ignored. Could be spurious response. } if ( tStatus & (NVEC_TRANSPORT_STATUS_EVENT_RECEIVE_ERROR | NVEC_TRANSPORT_STATUS_EVENT_RECEIVE_COMPLETE) ) { e = (tStatus & NVEC_TRANSPORT_STATUS_EVENT_RECEIVE_COMPLETE) ? NvSuccess : NvError_I2cReadFailed; e = NvEcPrivProcessReceiveEvent( ec, e ); // return ignored. Could be spurious event. } if ( tStatus & NVEC_TRANSPORT_STATUS_EVENT_PACKET_MAX_NACK ) { // signal the ping thread to send a ping command since max // number of nacks have been sent to the EC if (ec->hPingSema) { NvOsSemaphoreSignal(ec->hPingSema); } } // send request whenever possible if ( (ec->timeout[NVEC_IDX_REQUEST] == NV_WAIT_INFINITE) && (ec->EnterLowPowerState == NV_FALSE) ) NvEcPrivProcessSendRequest( ec ); #if ENABLE_TIMEOUT timeout = NvEcPrivUpdateActualTimeout( ec ); #endif if (ec->EnterLowPowerState) { // This code assumes that EC is already in kept in sleep mode by // either shim or top level code. And there will not be any activity // going on SM bus. if (ec->timeout[NVEC_IDX_REQUEST] != NV_WAIT_INFINITE) { NvOsDebugPrintf("\r\nNvEc has active requests during suspend. " "It shouldn't have. check it."); } // No active request is pending. Enter into low power state. // Signal power suspend API to enter into suspend mode. NvOsSemaphoreSignal(ec->LowPowerEntrySema); // Wait till power resume API signals resume operation. NvOsSemaphoreWait(ec->LowPowerExitSema); // Update the timeouts for the active responses, which are scheduled // to receive before system entering into suspend. #if ENABLE_TIMEOUT NvEcPrivResetActiveRequestResponseTimeouts( ec ); timeout = NvEcPrivUpdateActualTimeout( ec ); #endif // ENABLE_TIMEOUT } } }
NvError NvEcSendRequest( NvEcHandle hEc, NvEcRequest *pRequest, NvEcResponse *pResponse, NvU32 RequestSize, NvU32 ResponseSize) { NvEcPrivState *ec; NvError e = NvSuccess; NvEcRequestNode *requestNode = NULL; NvEcResponseNode *responseNode = NULL; NvOsSemaphoreHandle requestSema = NULL; NvOsSemaphoreHandle responseSema = NULL; NV_ASSERT( pRequest ); NV_ASSERT( hEc ); if ( (RequestSize > sizeof(NvEcRequest)) || (ResponseSize > sizeof(NvEcResponse)) ) return NvError_InvalidSize; ec = hEc->ec; requestNode = NvOsAlloc(sizeof(NvEcRequestNode)); if ( NULL == requestNode ) { e = NvError_InsufficientMemory; goto fail; } NV_CHECK_ERROR_CLEANUP( NvOsSemaphoreCreate( &requestSema, 0 ) ); if ( pResponse ) { responseNode = NvOsAlloc(sizeof(NvEcResponseNode)); if ( NULL == responseNode ) { e = NvError_InsufficientMemory; goto fail; } NV_CHECK_ERROR_CLEANUP( NvOsSemaphoreCreate( &responseSema, 0 ) ); } ec->IsEcActive = NV_TRUE; // request end-queue. Timeout set to infinite until request sent. NvOsMemset( requestNode, 0, sizeof(NvEcRequestNode) ); pRequest->RequestorTag = hEc->tag; // assigned tag here DISP_MESSAGE(("NvEcSendRequest:pRequest->RequestorTag=0x%x\n", pRequest->RequestorTag)); NvOsMemcpy(&requestNode->request, pRequest, RequestSize); requestNode->tag = hEc->tag; DISP_MESSAGE(("NvEcSendRequest:requestNode->tag=0x%x\n", requestNode->tag)); requestNode->sema = requestSema; requestNode->timeout = NV_WAIT_INFINITE; requestNode->completed = NV_FALSE; requestNode->size = RequestSize; NvOsMutexLock( ec->requestMutex ); NVEC_ENQ( ec->request, requestNode ); DISP_MESSAGE(("\r\nSendReq ec->requestBegin=0x%x", ec->requestBegin)); NvOsMutexUnlock( ec->requestMutex ); // response en-queue. Timeout set to infinite until request completes. if ( pResponse ) { NvOsMemset( responseNode, 0, sizeof(NvEcResponseNode) ); requestNode->responseNode = responseNode; // association between responseNode->requestNode = requestNode; // request & response responseNode->sema = responseSema; responseNode->timeout = NV_WAIT_INFINITE; responseNode->tag = hEc->tag; DISP_MESSAGE(("NvEcSendRequest:responseNode->tag=0x%x\n", responseNode->tag)); responseNode->size = ResponseSize; NvOsMutexLock( ec->responseMutex ); NVEC_ENQ( ec->response, responseNode ); DISP_MESSAGE(("\r\nSendReq ec->responseBegin=0x%x", ec->responseBegin)); NvOsMutexUnlock( ec->responseMutex ); } NvOsMutexLock( ec->mutex ); if ( !ec->thread ) NvEcPrivThreadCreate( ec ); NvOsMutexUnlock( ec->mutex ); // Trigger EcPrivThread NvOsSemaphoreSignal( ec->sema ); DISP_MESSAGE(("\r\nSendReq requestNode=0x%x, requestNode->responseNode=0x%x", requestNode, requestNode->responseNode)); // Wait on Request returns NvOsSemaphoreWait( requestSema ); DISP_MESSAGE(("\r\nSendReq Out of req sema")); e = requestNode->status; if ( NvSuccess != e ) { NvEcResponseNode *t = NULL, *p = NULL; // de-queue responseNode too !!!! NvOsMutexLock( ec->responseMutex ); NVEC_REMOVE_FROM_Q( ec->response, responseNode, t, p ); DISP_MESSAGE(("\r\nSendReq responseBegin=0x%x", ec->responseBegin)); NvOsMutexUnlock( ec->responseMutex ); goto fail; } if ( pResponse ) { // Wait on Response returns NvOsSemaphoreWait( responseSema ); DISP_MESSAGE(("\r\nSendReq Out of resp sema")); NV_CHECK_ERROR_CLEANUP( responseNode->status ); NvOsMemcpy(pResponse, &responseNode->response, ResponseSize); } // if successful, nodes should be de-queue already but not freed yet fail: NvOsSemaphoreDestroy( requestSema ); NvOsSemaphoreDestroy( responseSema ); DISP_MESSAGE(("\r\nSendReq Freeing requestNode=0x%x, responseNode=0x%x", requestNode, responseNode)); NvOsFree( requestNode ); NvOsFree( responseNode ); return e; }