Example #1
0
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;
}
Example #2
0
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;
}
Example #8
0
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;
}
Example #9
0
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;
}
Example #10
0
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;
}
Example #11
0
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;
}
Example #12
0
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;
}
Example #13
0
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;
}