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; }
NvError NvDdkUsbPhyOpen( NvRmDeviceHandle hRm, NvU32 Instance, NvDdkUsbPhyHandle *hUsbPhy) { NvError e; NvU32 MaxInstances = 0; NvDdkUsbPhy *pUsbPhy = NULL; NvOsMutexHandle UsbPhyMutex = NULL; NvRmModuleInfo info[MAX_USB_INSTANCES]; NvU32 j; NV_ASSERT(hRm); NV_ASSERT(hUsbPhy); NV_ASSERT(Instance < MAX_USB_INSTANCES); NV_CHECK_ERROR(NvRmModuleGetModuleInfo( hRm, NvRmModuleID_Usb2Otg, &MaxInstances, NULL )); if (MaxInstances > MAX_USB_INSTANCES) { // Ceil "instances" to MAX_USB_INSTANCES MaxInstances = MAX_USB_INSTANCES; } NV_CHECK_ERROR(NvRmModuleGetModuleInfo( hRm, NvRmModuleID_Usb2Otg, &MaxInstances, info )); for (j = 0; j < MaxInstances; j++) { // Check whether the requested instance is present if(info[j].Instance == Instance) break; } // No match found return if (j == MaxInstances) { return NvError_ModuleNotPresent; } if (!s_UsbPhyMutex) { e = NvOsMutexCreate(&UsbPhyMutex); if (e!=NvSuccess) return e; if (NvOsAtomicCompareExchange32( (NvS32*)&s_UsbPhyMutex, 0, (NvS32)UsbPhyMutex)!=0) { NvOsMutexDestroy(UsbPhyMutex); } } NvOsMutexLock(s_UsbPhyMutex); if (!s_pUsbPhy) { s_pUsbPhy = NvOsAlloc(MaxInstances * sizeof(NvDdkUsbPhy)); if (s_pUsbPhy) NvOsMemset(s_pUsbPhy, 0, MaxInstances * sizeof(NvDdkUsbPhy)); } NvOsMutexUnlock(s_UsbPhyMutex); if (!s_pUsbPhy) return NvError_InsufficientMemory; NvOsMutexLock(s_UsbPhyMutex); if (!s_pUtmiPadConfig) { s_pUtmiPadConfig = NvOsAlloc(sizeof(NvDdkUsbPhyUtmiPadConfig)); if (s_pUtmiPadConfig) { NvRmPhysAddr PhyAddr; NvOsMemset(s_pUtmiPadConfig, 0, sizeof(NvDdkUsbPhyUtmiPadConfig)); NvRmModuleGetBaseAddress( hRm, NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, 0), &PhyAddr, &s_pUtmiPadConfig->BankSize); NV_CHECK_ERROR_CLEANUP( NvRmPhysicalMemMap( PhyAddr, s_pUtmiPadConfig->BankSize, NVOS_MEM_READ_WRITE, NvOsMemAttribute_Uncached, (void **)&s_pUtmiPadConfig->pVirAdr)); } } NvOsMutexUnlock(s_UsbPhyMutex); if (!s_pUtmiPadConfig) return NvError_InsufficientMemory; pUsbPhy = &s_pUsbPhy[Instance]; NvOsMutexLock(s_UsbPhyMutex); if (!pUsbPhy->RefCount) { NvRmPhysAddr PhysAddr; NvOsMutexHandle ThreadSafetyMutex = NULL; NvOsMemset(pUsbPhy, 0, sizeof(NvDdkUsbPhy)); pUsbPhy->Instance = Instance; pUsbPhy->hRmDevice = hRm; pUsbPhy->RefCount = 1; pUsbPhy->IsPhyPoweredUp = NV_FALSE; pUsbPhy->pUtmiPadConfig = s_pUtmiPadConfig; pUsbPhy->pProperty = NvOdmQueryGetUsbProperty( NvOdmIoModule_Usb, pUsbPhy->Instance); pUsbPhy->TurnOffPowerRail = UsbPhyTurnOffPowerRail(MaxInstances); NV_CHECK_ERROR_CLEANUP(NvOsMutexCreate(&ThreadSafetyMutex)); if (NvOsAtomicCompareExchange32( (NvS32*)&pUsbPhy->ThreadSafetyMutex, 0, (NvS32)ThreadSafetyMutex)!=0) { NvOsMutexDestroy(ThreadSafetyMutex); } NvRmModuleGetBaseAddress( pUsbPhy->hRmDevice, NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, pUsbPhy->Instance), &PhysAddr, &pUsbPhy->UsbBankSize); NV_CHECK_ERROR_CLEANUP( NvRmPhysicalMemMap( PhysAddr, pUsbPhy->UsbBankSize, NVOS_MEM_READ_WRITE, NvOsMemAttribute_Uncached, (void **)&pUsbPhy->UsbVirAdr)); NvRmModuleGetBaseAddress( pUsbPhy->hRmDevice, NVRM_MODULE_ID(NvRmModuleID_Misc, 0), &PhysAddr, &pUsbPhy->MiscBankSize); NV_CHECK_ERROR_CLEANUP( NvRmPhysicalMemMap( PhysAddr, pUsbPhy->MiscBankSize, NVOS_MEM_READ_WRITE, NvOsMemAttribute_Uncached, (void **)&pUsbPhy->MiscVirAdr)); if ( ( pUsbPhy->pProperty->UsbInterfaceType == NvOdmUsbInterfaceType_UlpiNullPhy) || ( pUsbPhy->pProperty->UsbInterfaceType == NvOdmUsbInterfaceType_UlpiExternalPhy)) { if (NvRmSetModuleTristate( pUsbPhy->hRmDevice, NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, pUsbPhy->Instance), NV_FALSE) != NvSuccess ) return NvError_NotSupported; } // Register with Power Manager NV_CHECK_ERROR_CLEANUP( NvOsSemaphoreCreate(&pUsbPhy->hPwrEventSem, 0)); pUsbPhy->RmPowerClientId = NVRM_POWER_CLIENT_TAG('U','S','B','p'); NV_CHECK_ERROR_CLEANUP( NvRmPowerRegister(pUsbPhy->hRmDevice, pUsbPhy->hPwrEventSem, &pUsbPhy->RmPowerClientId)); // Open the H/W interface UsbPhyOpenHwInterface(pUsbPhy); // Initialize the USB Phy NV_CHECK_ERROR_CLEANUP(UsbPhyInitialize(pUsbPhy)); } else { pUsbPhy->RefCount++; } *hUsbPhy = pUsbPhy; NvOsMutexUnlock(s_UsbPhyMutex); return NvSuccess; fail: NvDdkUsbPhyClose(pUsbPhy); NvOsMutexUnlock(s_UsbPhyMutex); return e; }