NvError AddKeyToList(NvU32 KeyID, NvU32 Value) { Key *pList; if (s_pKeyList->Count < NVRM_KEY_ARRAY_LEN) { s_pKeyList->KeyID[s_pKeyList->Count] = KeyID; s_pKeyList->Value[s_pKeyList->Count] = Value; s_pKeyList->Count++; } else { pList = NvOsAlloc(sizeof(Key)); if (pList == NULL) return NvError_InsufficientMemory; pList->KeyID[0] = KeyID; pList->Value[0] = Value; pList->Count = 1; pList->pNextKey = s_pKeyList; s_pKeyList = pList; } return NvSuccess; }
static BusyHintReq* BusyReqAlloc(void) { if (s_FreeBusyReqPoolSize != 0) return s_pFreeBusyReqPool[--s_FreeBusyReqPoolSize]; else { NV_ASSERT(!"Busy pool size is too small"); return NvOsAlloc(sizeof(BusyHintReq)); } }
void NvRmPrivGetCpuIdInfo(NvU32 *id,NvU32 *family,NvU32 *major,NvU32 *minor,NvU32 *sku) { #define TAG "GetCpuIdInfo: " NvRmDeviceHandle rm; rm=(NvRmDeviceHandle)NvOsAlloc(sizeof(NvRmDevice)); if(rm==NULL) { NvOsDebugPrintf(TAG "NvOsAlloc rm fail!\n"); return; } NvRmPrivReadChipId(rm); #if 0 typedef enum { NvRmChipFamily_Gpu = 0, NvRmChipFamily_Handheld = 1, NvRmChipFamily_BrChips = 2, NvRmChipFamily_Crush = 3, NvRmChipFamily_Mcp = 4, NvRmChipFamily_Ck = 5, NvRmChipFamily_Vaio = 6, NvRmChipFamily_HandheldSoc = 7, NvRmChipFamily_Force32 = 0x7FFFFFFF, } NvRmChipFamily; #endif if(id!=NULL) *id=rm->ChipId.Id; if(family!=NULL) *family=rm->ChipId.Family; if(major!=NULL) *major=rm->ChipId.Family; if(minor!=NULL) *minor=rm->ChipId.Minor; if(sku!=NULL) *sku=rm->ChipId.SKU; /*if(id!=NULL&&family!=NULL&&major!=NULL&&minor!=NULL&&sku!=NULL) NvOsDebugPrintf( "second Chip Id: 0x%x Family:0x%x Major: 0x%x Minor: 0x%x " "SKU: 0x%x\n", *id,*family, *major, *minor, *sku );*/ NvOsFree(rm); }
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 NvEcRegisterForEvents( NvEcHandle hEc, NvEcEventRegistrationHandle *phEcEventRegistration, NvOsSemaphoreHandle hSema, NvU32 NumEventTypes, NvEcEventType *pEventTypes, NvU32 NumEventPackets, NvU32 EventPacketSize) { NvEcPrivState *ec = hEc->ec; NvEcEventRegistration *h = NULL; NvOsSemaphoreHandle hSemaClone = NULL; NvError e = NvSuccess; NvU32 val, i, tag = hEc->tag; NvU32 tagMask = (1UL << tag); if ( !hSema || !pEventTypes ) return NvError_BadParameter; if ( !NumEventTypes || (NumEventTypes > NvEcEventType_Num) ) return NvError_InvalidSize; // FIXME: is this sufficient? NV_ASSERT( phEcEventRegistration ); NvOsMutexLock( ec->mutex ); if ( !ec->thread ) NvEcPrivThreadCreate( ec ); // Allocate common pool of internal event nodes bufferring if not already if ( !ec->eventNodes ) { val = NVEC_NUM_EVENT_PACKETS_DEFAULT; if ( NumEventPackets > val ) val = NumEventPackets; ec->eventNodes = NvOsAlloc(val * sizeof(NvEcEventNode)); if ( NULL == ec->eventNodes ) { NvOsMutexUnlock( ec->mutex ); return NvError_InsufficientMemory; } NvOsMemset( ec->eventNodes, 0, (val * sizeof(NvEcEventNode)) ); for( i = 0; i < val - 1; i++ ) ec->eventNodes[i].next = &ec->eventNodes[i+1]; ec->eventFreeBegin = ec->eventNodes; ec->eventFreeEnd = ec->eventNodes + val - 1; } NvOsMutexUnlock( ec->mutex ); NV_CHECK_ERROR( NvOsSemaphoreClone( hSema, &hSemaClone ) ); NvOsMutexLock( ec->eventMutex ); // Quick pre-check for for AlreadyAllocated case for ( i = 0; i < NumEventTypes; i++ ) { val = pEventTypes[i]; if ( val >= NvEcEventType_Num ) e = NvError_BadParameter; else if ( ec->eventMap[tag][val] ) e = NvError_AlreadyAllocated; if ( NvSuccess != e ) goto fail; } h = NvOsAlloc( sizeof(NvEcEventRegistration)); if ( NULL == h ) { e = NvError_InsufficientMemory; goto fail; } NvOsMemset( h, 0, sizeof(NvEcEventRegistration) ); NVEC_ENQ( ec->eventReg[tag].reg, h ); // Fill up new registration handle NV_ASSERT( NvEcEventType_Num <= 32 ); // eventBitmap only works if <= 32 for ( i = 0; i < NumEventTypes; i++ ) { val = pEventTypes[i]; h->eventBitmap |= (1 << val); ec->eventMap[tag][val] = h; ec->eventTagBitmap[val] |= tagMask; } h->numEventTypes = NumEventTypes; h->sema = hSemaClone; h->hEc = hEc; h->numEventPacketsHint = NumEventPackets; h->eventPacketSizeHint = EventPacketSize; // ignored hints for now NvOsMutexUnlock( ec->eventMutex ); *phEcEventRegistration = h; return e; fail: NvOsSemaphoreDestroy( hSemaClone ); NvOsMutexUnlock( ec->eventMutex ); NvOsFree( h ); return e; }
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; }
long nvrm_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { NvError err; NvOsIoctlParams p; NvU32 size; NvU32 small_buf[8]; void *ptr = 0; long e; NvBool bAlloc = NV_FALSE; struct nvrm_file_priv *priv = file->private_data; switch( cmd ) { case NvRmIoctls_Generic: { NvDispatchCtx dctx; dctx.Rt = s_RtHandle; dctx.Client = priv->rt_client; dctx.PackageIdx = 0; err = NvOsCopyIn( &p, (void *)arg, sizeof(p) ); if( err != NvSuccess ) { printk( "NvRmIoctls_Generic: copy in failed\n" ); goto fail; } //printk( "NvRmIoctls_Generic: %d %d %d\n", p.InBufferSize, // p.InOutBufferSize, p.OutBufferSize ); size = p.InBufferSize + p.InOutBufferSize + p.OutBufferSize; if( size <= sizeof(small_buf) ) { ptr = small_buf; } else { ptr = NvOsAlloc( size ); if( !ptr ) { printk( "NvRmIoctls_Generic: alloc failure (%d bytes)\n", size ); goto fail; } bAlloc = NV_TRUE; } err = NvOsCopyIn( ptr, p.pBuffer, p.InBufferSize + p.InOutBufferSize ); if( err != NvSuccess ) { printk( "NvRmIoctls_Generic: copy in failure\n" ); goto fail; } if (priv->su) { err = NvRm_Dispatch( ptr, p.InBufferSize + p.InOutBufferSize, ((NvU8 *)ptr) + p.InBufferSize, p.InOutBufferSize + p.OutBufferSize, &dctx ); } else { err = NvRm_Dispatch_Others( ptr, p.InBufferSize + p.InOutBufferSize, ((NvU8 *)ptr) + p.InBufferSize, p.InOutBufferSize + p.OutBufferSize, &dctx ); } if( err != NvSuccess ) { printk( "NvRmIoctls_Generic: dispatch failure\n" ); goto fail; } if( p.InOutBufferSize || p.OutBufferSize ) { err = NvOsCopyOut( ((NvU8 *)((NvOsIoctlParams *)arg)->pBuffer) + p.InBufferSize, ((NvU8 *)ptr) + p.InBufferSize, p.InOutBufferSize + p.OutBufferSize ); if( err != NvSuccess ) { printk( "NvRmIoctls_Generic: copy out failure\n" ); goto fail; } } break; } case NvRmIoctls_NvRmGraphics: printk( "NvRmIoctls_NvRmGraphics: not supported\n" ); goto fail; case NvRmIoctls_NvRmFbControl: printk( "NvRmIoctls_NvRmFbControl: deprecated \n" ); break; case NvRmIoctls_NvRmMemRead: case NvRmIoctls_NvRmMemWrite: case NvRmIoctls_NvRmMemReadStrided: case NvRmIoctls_NvRmGetCarveoutInfo: case NvRmIoctls_NvRmMemWriteStrided: goto fail; case NvRmIoctls_NvRmMemMapIntoCallerPtr: // FIXME: implement? printk( "NvRmIoctls_NvRmMemMapIntoCallerPtr: not supported\n" ); goto fail; case NvRmIoctls_NvRmBootDone: return tegra_start_dvfsd(); case NvRmIoctls_NvRmGetClientId: err = NvOsCopyIn(&p, (void*)arg, sizeof(p)); if (err != NvSuccess) { NvOsDebugPrintf("NvRmIoctls_NvRmGetClientId: copy in failed\n"); goto fail; } NV_ASSERT(p.InBufferSize == 0); NV_ASSERT(p.OutBufferSize == sizeof(NvRtClientHandle)); NV_ASSERT(p.InOutBufferSize == 0); if (NvOsCopyOut(p.pBuffer, &priv->rt_client, sizeof(NvRtClientHandle)) != NvSuccess) { NvOsDebugPrintf("Failed to copy client id\n"); goto fail; } break; case NvRmIoctls_NvRmClientAttach: { NvRtClientHandle Client; err = NvOsCopyIn(&p, (void*)arg, sizeof(p)); if (err != NvSuccess) { NvOsDebugPrintf("NvRmIoctls_NvRmClientAttach: copy in failed\n"); goto fail; } NV_ASSERT(p.InBufferSize == sizeof(NvRtClientHandle)); NV_ASSERT(p.OutBufferSize == 0); NV_ASSERT(p.InOutBufferSize == 0); if (NvOsCopyIn((void*)&Client, p.pBuffer, sizeof(NvRtClientHandle)) != NvSuccess) { NvOsDebugPrintf("Failed to copy client id\n"); goto fail; } NV_ASSERT(Client || !"Bad client"); if (Client == priv->rt_client) { // The daemon is attaching to itself, no need to add refcount break; } if (NvRtAddClientRef(s_RtHandle, Client) != NvSuccess) { NvOsDebugPrintf("Client ref add unsuccessful\n"); goto fail; } break; } case NvRmIoctls_NvRmClientDetach: { NvRtClientHandle Client; err = NvOsCopyIn(&p, (void*)arg, sizeof(p)); if (err != NvSuccess) { NvOsDebugPrintf("NvRmIoctls_NvRmClientAttach: copy in failed\n"); goto fail; } NV_ASSERT(p.InBufferSize == sizeof(NvRtClientHandle)); NV_ASSERT(p.OutBufferSize == 0); NV_ASSERT(p.InOutBufferSize == 0); if (NvOsCopyIn((void*)&Client, p.pBuffer, sizeof(NvRtClientHandle)) != NvSuccess) { NvOsDebugPrintf("Failed to copy client id\n"); goto fail; } NV_ASSERT(Client || !"Bad client"); if (Client == priv->rt_client) { // The daemon is detaching from itself, no need to dec refcount break; } client_detach(Client); break; } // FIXME: power ioctls? default: printk( "unknown ioctl code\n" ); goto fail; } e = 0; goto clean; fail: e = -EINVAL; clean: if( bAlloc ) { NvOsFree( ptr ); } return e; }
NvError NvRmPowerVoltageControl( NvRmDeviceHandle hRmDeviceHandle, NvRmModuleID ModuleId, NvU32 ClientId, NvRmMilliVolts MinVolts, NvRmMilliVolts MaxVolts, const NvRmMilliVolts* PrefVoltageList, NvU32 PrefVoltageListCount, NvRmMilliVolts* pCurrentVolts) { NvError error; NvU32 PowerGroup = 0; NvBool PowerChanged = NV_FALSE; NvRmModuleInstance *pInstance = NULL; ModuleVoltageReq* pVoltageReq = NULL; NvRmPowerClient* pPowerClient = NULL; NvRmPowerRegistry* pRegistry = &s_PowerRegistry; NvU32 ClientIndex = NVRM_POWER_ID2INDEX(ClientId); /* validate the Rm Handle */ NV_ASSERT(hRmDeviceHandle); // Validate module ID and get associated Power Group if (ModuleId == NvRmPrivModuleID_System) { PowerGroup = NVRM_POWERGROUP_NPG_AUTO; } else { error = NvRmPrivGetModuleInstance(hRmDeviceHandle, ModuleId, &pInstance); if (error != NvSuccess) { NV_ASSERT(!" Voltage control: Invalid module ID. "); return NvError_ModuleNotPresent; } PowerGroup = pInstance->DevPowerGroup; NV_ASSERT(PowerGroup < NV_POWERGROUP_MAX); } NvOsMutexLock(s_hPowerClientMutex); // Check if this ID was registered; return error otherwise if (ClientIndex < pRegistry->UsedIndexRange) { pPowerClient = pRegistry->pPowerClients[ClientIndex]; } if ((pPowerClient == NULL) || (pPowerClient->id != ClientId)) { NvOsMutexUnlock(s_hPowerClientMutex); return NvError_BadValue; } // Search for the previously recorded voltage request for this module pVoltageReq = pPowerClient->pVoltageReqHead; while ((pVoltageReq != NULL) && (pVoltageReq->ModuleId != ModuleId)) { pVoltageReq = pVoltageReq->pNext; } // If it is a new voltage request record, allocate and fill it in, // otherwise just update power status. In both cases determine if // power requirements for the module have changed. if (pVoltageReq == NULL) { pVoltageReq = NvOsAlloc(sizeof(*pVoltageReq)); if (pVoltageReq == NULL) { NvOsMutexUnlock(s_hPowerClientMutex); return NvError_InsufficientMemory; } // Link at head pVoltageReq->pNext = pPowerClient->pVoltageReqHead; pPowerClient->pVoltageReqHead = pVoltageReq; pVoltageReq->ModuleId = ModuleId; pVoltageReq->PowerGroup = PowerGroup; pVoltageReq->PowerCycled = NV_FALSE; // Only new power On request counts as change PowerChanged = (MaxVolts != NvRmVoltsOff); } else { // Only changes from On to Off or vice versa counts PowerChanged = (pVoltageReq->MaxVolts != MaxVolts) && ((pVoltageReq->MaxVolts == NvRmVoltsOff) || (MaxVolts == NvRmVoltsOff)); } // Record new power request voltages pVoltageReq->MinVolts = MinVolts; pVoltageReq->MaxVolts = MaxVolts; // If module power requirements have changed, update power group reference // count, and execute the respective h/w power control procedure if (PowerChanged) { if (MaxVolts != NvRmVoltsOff) { s_PowerOnRefCounts[PowerGroup]++; if (s_PowerOnRefCounts[PowerGroup] == 1) { NvRmMilliVolts v = NvRmPrivPowerGroupGetVoltage(hRmDeviceHandle, PowerGroup); if (v == NvRmVoltsOff) { RecordPowerCycle(hRmDeviceHandle, PowerGroup); NvRmPrivPowerGroupControl(hRmDeviceHandle, PowerGroup, NV_TRUE); } } } else { NV_ASSERT(s_PowerOnRefCounts[PowerGroup] != 0); if (s_PowerOnRefCounts[PowerGroup] == 0) { NVRM_POWER_PRINTF(("Power balance failed: module %d\n", ModuleId)); } s_PowerOnRefCounts[PowerGroup]--; if (s_PowerOnRefCounts[PowerGroup] == 0) { NvRmPrivPowerGroupControl(hRmDeviceHandle, PowerGroup, NV_FALSE); } } } ReportRmPowerState(hRmDeviceHandle); // Return current voltage, unless this is the first request after module // was power cycled by RM; in the latter case return NvRmVoltsCycled value if (pCurrentVolts != NULL) { *pCurrentVolts = NvRmPrivPowerGroupGetVoltage(hRmDeviceHandle, PowerGroup); if (pVoltageReq->PowerCycled && (*pCurrentVolts != NvRmVoltsOff)) { *pCurrentVolts = NvRmVoltsCycled; } } // In any case clear power cycled indicator pVoltageReq->PowerCycled = NV_FALSE; NvOsMutexUnlock(s_hPowerClientMutex); return NvSuccess; }
NvError NvRmPowerRegister( NvRmDeviceHandle hRmDeviceHandle, NvOsSemaphoreHandle hEventSemaphore, NvU32* pClientId) { NvU32 FreeIndex; NvError error; NvOsSemaphoreHandle hSema = NULL; NvRmPowerClient* pNewClient = NULL; NvRmPowerRegistry* pRegistry = &s_PowerRegistry; NV_ASSERT(hRmDeviceHandle); NV_ASSERT(pClientId); // If non-zero semaphore handle is passed, duplicate it to be avialable // after the call. Abort registration if non-zero handle is invalid if (hEventSemaphore != NULL) { error = NvOsSemaphoreClone(hEventSemaphore, &hSema); if (error != NvSuccess) { NV_ASSERT(!" Power Register Semaphore Clone error. "); } } NvOsMutexLock(s_hPowerClientMutex); // Find free registry entry for the new client for (FreeIndex = 0; FreeIndex < pRegistry->UsedIndexRange; FreeIndex++) { if (pRegistry->pPowerClients[FreeIndex] == NULL) break; } if (FreeIndex == pRegistry->AvailableEntries) { // If all avilable entries are used, re-size registry array NvU32 entries = pRegistry->AvailableEntries + NVRM_POWER_REGISTRY_DELTA; size_t s = sizeof(*pRegistry->pPowerClients) * (size_t)entries; NvRmPowerClient** p = NvOsRealloc(pRegistry->pPowerClients, s); if (p == NULL) { NvU32 old_size; /* fall back to NvOsAlloc */ p = NvOsAlloc( s ); if( p == NULL ) { goto failed; } /* copy the old data, free, etc, */ old_size = sizeof(*pRegistry->pPowerClients) * pRegistry->AvailableEntries; NvOsMemcpy( p, pRegistry->pPowerClients, old_size ); NvOsFree( pRegistry->pPowerClients ); } pRegistry->pPowerClients = p; pRegistry->AvailableEntries = entries; } if (FreeIndex == pRegistry->UsedIndexRange) { // If reached used index range boundary, advance it pRegistry->UsedIndexRange++; } // Allocate and store new client record pointer in registry (null-pointer // marks registry entry as free, so it's OK to store it before error check) pNewClient = NvOsAlloc(sizeof(*pNewClient)); pRegistry->pPowerClients[FreeIndex] = pNewClient; if (pNewClient == NULL) { goto failed; } // Fill in new client entry pNewClient->hEventSemaphore = hSema; pNewClient->Event = NvRmPowerEvent_NoEvent; pNewClient->pVoltageReqHead = NULL; pNewClient->pClockReqHead = NULL; pNewClient->pStarvationHints = NULL; pNewClient->tag = *pClientId; /* * Combine index with client pointer into registration ID returned to the * client. This will make it a little bit more difficult for not-registered * clients to guess/re-use IDs */ pNewClient->id = NVRM_POWER_INDEX2ID(FreeIndex, (NvU32)pClientId); *pClientId = pNewClient->id; NvOsMutexUnlock(s_hPowerClientMutex); return NvSuccess; failed: NvOsFree(pNewClient); NvOsSemaphoreDestroy(hSema); NvOsMutexUnlock(s_hPowerClientMutex); return NvError_InsufficientMemory; }
static NvError RecordStarvationHints( NvRmDeviceHandle hRmDeviceHandle, NvRmPowerClient* pPowerClient, const NvRmDfsStarvationHint* pMultiHint, NvU32 NumHints) { NvU32 i; NvBool HintChanged = NV_FALSE; for (i = 0; i < NumHints; i++) { NvRmDfsClockId ClockId = pMultiHint[i].ClockId; NvBool Starving = pMultiHint[i].Starving; NV_ASSERT((0 < ClockId) && (ClockId < NvRmDfsClockId_Num)); /* * If this is the first starvation hint, allocate hints array and fill * it in. Otherwise, just update starvation hint status. In both cases * determine if starvation hint for clock domain has changed. */ if (pPowerClient->pStarvationHints == NULL) { size_t s = sizeof(NvBool) * (size_t)NvRmDfsClockId_Num; NvBool* p = NvOsAlloc(s); if (p == NULL) { return NvError_InsufficientMemory; } NvOsMemset(p, 0, s); pPowerClient->pStarvationHints = p; // Only new Satrvation On hint counts as change HintChanged = Starving; } else { // Only changes from On to Off or vice versa counts HintChanged = (pPowerClient->pStarvationHints[ClockId] != Starving); } pPowerClient->pStarvationHints[ClockId] = Starving; // If hint has changed, update clock domain starvation reference count // (hint against CPU, or AVP, or VDE is automatically applied to EMC) if (HintChanged) { if (Starving) { if ((ClockId == NvRmDfsClockId_Cpu) || (ClockId == NvRmDfsClockId_Avp) || (ClockId == NvRmDfsClockId_Vpipe)) { s_StarveOnRefCounts[NvRmDfsClockId_Emc]++; } s_StarveOnRefCounts[ClockId]++; } else { if ((ClockId == NvRmDfsClockId_Cpu) || (ClockId == NvRmDfsClockId_Avp) || (ClockId == NvRmDfsClockId_Vpipe)) { NV_ASSERT(s_StarveOnRefCounts[NvRmDfsClockId_Emc] != 0); s_StarveOnRefCounts[NvRmDfsClockId_Emc]--; } NV_ASSERT(s_StarveOnRefCounts[ClockId] != 0); s_StarveOnRefCounts[ClockId]--; } } } return NvSuccess; }
NvError NvRmPwmOpen( NvRmDeviceHandle hDevice, NvRmPwmHandle *phPwm) { NvError status = NvSuccess; NvU32 PwmPhysAddr = 0, i = 0, PmcPhysAddr = 0; NvRmModuleCapability caps[4]; NvRmModuleCapability *pCap = NULL; NV_ASSERT(hDevice); NV_ASSERT(phPwm); NvOsMutexLock(s_hPwmMutex); if (s_hPwm) { s_hPwm->RefCount++; goto exit; } // Allcoate the memory for the pwm handle s_hPwm = NvOsAlloc(sizeof(NvRmPwm)); if (!s_hPwm) { status = NvError_InsufficientMemory; goto fail; } NvOsMemset(s_hPwm, 0, sizeof(NvRmPwm)); // Set the pwm handle parameters s_hPwm->RmDeviceHandle = hDevice; // Get the pwm physical and virtual base address NvRmModuleGetBaseAddress(hDevice, NVRM_MODULE_ID(NvRmModuleID_Pwm, 0), &PwmPhysAddr, &(s_hPwm->PwmBankSize)); s_hPwm->PwmBankSize = PWM_BANK_SIZE; for (i = 0; i < NvRmPwmOutputId_Num-2; i++) { status = NvRmPhysicalMemMap( PwmPhysAddr + i*s_hPwm->PwmBankSize, s_hPwm->PwmBankSize, NVOS_MEM_READ_WRITE, NvOsMemAttribute_Uncached, (void**)&s_hPwm->VirtualAddress[i]); if (status != NvSuccess) { NvOsFree(s_hPwm); goto fail; } } // Get the pmc physical and virtual base address NvRmModuleGetBaseAddress(hDevice, NVRM_MODULE_ID(NvRmModuleID_Pmif, 0), &PmcPhysAddr, &(s_hPwm->PmcBankSize)); s_hPwm->PmcBankSize = PMC_BANK_SIZE; status = NvRmPhysicalMemMap( PmcPhysAddr, s_hPwm->PmcBankSize, NVOS_MEM_READ_WRITE, NvOsMemAttribute_Uncached, (void**)&s_hPwm->VirtualAddress[NvRmPwmOutputId_Num-2]); if (status != NvSuccess) { NvOsFree(s_hPwm); goto fail; } caps[0].MajorVersion = 1; caps[0].MinorVersion = 0; caps[0].EcoLevel = 0; caps[0].Capability = &caps[0]; caps[1].MajorVersion = 1; caps[1].MinorVersion = 1; caps[1].EcoLevel = 0; caps[1].Capability = &caps[1]; caps[2].MajorVersion = 1; caps[2].MinorVersion = 2; caps[2].EcoLevel = 0; caps[2].Capability = &caps[2]; caps[3].MajorVersion = 2; caps[3].MinorVersion = 0; caps[3].EcoLevel = 0; caps[3].Capability = &caps[3]; NV_ASSERT_SUCCESS(NvRmModuleGetCapabilities( hDevice, NvRmModuleID_Pwm, caps, sizeof(caps)/sizeof(caps[0]), (void**)&pCap)); if ((pCap->MajorVersion > 1) || ((pCap->MajorVersion == 1) && (pCap->MinorVersion > 0))) s_IsFreqDividerSupported = NV_TRUE; s_hPwm->RefCount++; exit: *phPwm = s_hPwm; NvOsMutexUnlock(s_hPwmMutex); return NvSuccess; fail: NvOsMutexUnlock(s_hPwmMutex); return status; }
long nvec_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { NvError err; NvOsIoctlParams p; NvU32 size; NvU32 small_buf[8]; void *ptr = 0; long e; NvBool bAlloc = NV_FALSE; switch( cmd ) { case NvECKernelIoctls_Generic: { NvDispatchCtx dctx; dctx.Rt = s_RtHandle; dctx.Client = (NvRtClientHandle)file->private_data; dctx.PackageIdx = 0; err = NvOsCopyIn(&p, (void *)arg, sizeof(p)); if (err != NvSuccess) { printk("NvECKernelIoctls_Generic: copy in failed\n"); goto fail; } size = p.InBufferSize + p.InOutBufferSize + p.OutBufferSize; if (size <= sizeof(small_buf)) { ptr = small_buf; } else { ptr = NvOsAlloc(size); if (!ptr) { printk("NvECKernelIoctls_Generic: alloc err\n"); goto fail; } bAlloc = NV_TRUE; } err = NvOsCopyIn(ptr, p.pBuffer, p.InBufferSize + p.InOutBufferSize); if (err != NvSuccess) { printk("NvECKernelIoctls_Generic: copy in failure\n"); goto fail; } err = NvECPackage_Dispatch(ptr, p.InBufferSize + p.InOutBufferSize, ((NvU8 *)ptr) + p.InBufferSize, p.InOutBufferSize + p.OutBufferSize, &dctx); if (err != NvSuccess) { printk("NvECKernelIoctls_Generic: dispatch failure\n"); goto fail; } if (p.InOutBufferSize || p.OutBufferSize) { err = NvOsCopyOut( ((NvU8 *)((NvOsIoctlParams *)arg)->pBuffer) + p.InBufferSize, ((NvU8 *)ptr) + p.InBufferSize, p.InOutBufferSize + p.OutBufferSize); if (err != NvSuccess) { printk("NvECKernelIoctls_Generic: copyout err\n"); goto fail; } } break; } default: printk("unknown ioctl code\n"); goto fail; } e = 0; goto clean; fail: e = -EINVAL; clean: if (bAlloc) NvOsFree(ptr); return e; }
void *NvOdmOsAlloc(size_t size) { return NvOsAlloc( size ); }
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; }