Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/nvidia/arch/nvalloc/unix/include/nv-priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,9 @@ typedef struct nv_dynamic_power_s
PORT_ATOMIC nv_dynamic_power_state_t state;
NvS32 refcount;

/* Coalesced NVPCF notification to replay after runtime resume. */
NvBool nvpcf_notify_pending;

/*
* A word on lock ordering. These locks must be taken in the order:
*
Expand Down
1 change: 1 addition & 0 deletions src/nvidia/arch/nvalloc/unix/include/osapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ NV_STATUS RmPowerManagementTegra (OBJGPU *pGpu, nv_pm_action_t pmAction);
NV_STATUS os_ref_dynamic_power (nv_state_t *, nv_dynamic_power_mode_t);
void os_unref_dynamic_power (nv_state_t *, nv_dynamic_power_mode_t);
void RmHandleDisplayChange (nvidia_stack_t *, nv_state_t *);
NvBool RmDeferNvpcfNotifyIfIdle (nv_state_t *);
void RmUpdateGc6ConsoleRefCount (nv_state_t *, NvBool);

NvBool rm_get_uefi_console_status (nv_state_t *);
Expand Down
77 changes: 77 additions & 0 deletions src/nvidia/arch/nvalloc/unix/src/dynamic-power.c
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,8 @@ static void RmScheduleCallbackToIndicateIdle(OBJGPU *);
static NvBool RmCheckForGcxSupportOnCurrentState(OBJGPU *);
static void RmScheduleCallbackToRemoveIdleHoldoff(OBJGPU *);
static void RmQueueIdleSustainedWorkitem(OBJGPU *);
static void RmReplayNvpcfNotify(NvU32, void *);
static void RmQueueNvpcfReplay(OBJGPU *);

/*!
* @brief Wrapper that checks lock order for the dynamic power mutex. Locking
Expand Down Expand Up @@ -374,6 +376,7 @@ static void RmForceGpuNotIdle(
nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
nv_dynamic_power_state_t old_state;
NvBool ret;
NvBool bReplayNvpcf = NV_FALSE;

acquireDynamicPowerMutex(nvp);

Expand All @@ -383,6 +386,8 @@ static void RmForceGpuNotIdle(
{
case NV_DYNAMIC_POWER_STATE_IDLE_INDICATED:
nv_indicate_not_idle(nv);
bReplayNvpcf = nvp->dynamic_power.nvpcf_notify_pending;
nvp->dynamic_power.nvpcf_notify_pending = NV_FALSE;
NV_ASSERT(nvp->dynamic_power.deferred_idle_enabled);
RmScheduleCallbackForIdlePreConditions(pGpu);
/* fallthrough */
Expand All @@ -407,6 +412,11 @@ static void RmForceGpuNotIdle(
nv_release_mmap_lock(nv);

releaseDynamicPowerMutex(nvp);

if (bReplayNvpcf)
{
RmQueueNvpcfReplay(pGpu);
}
}

/*!
Expand Down Expand Up @@ -1109,6 +1119,7 @@ os_ref_dynamic_power(
nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
NV_STATUS status = NV_OK;
NvS32 ref;
NvBool bReplayNvpcf = NV_FALSE;

if (nvp == NULL)
{
Expand Down Expand Up @@ -1163,6 +1174,8 @@ os_ref_dynamic_power(
nvp->dynamic_power.refcount--;
break;
}
bReplayNvpcf = nvp->dynamic_power.nvpcf_notify_pending;
nvp->dynamic_power.nvpcf_notify_pending = NV_FALSE;
if (nvp->dynamic_power.deferred_idle_enabled)
{
RmScheduleCallbackForIdlePreConditions(NV_GET_NV_PRIV_PGPU(nv));
Expand All @@ -1185,6 +1198,11 @@ os_ref_dynamic_power(

releaseDynamicPowerMutex(nvp);

if (bReplayNvpcf)
{
RmQueueNvpcfReplay(NV_GET_NV_PRIV_PGPU(nv));
}

return status;
}

Expand Down Expand Up @@ -1459,6 +1477,65 @@ static void RmRemoveIdleHoldoff(
}
}

static void RmReplayNvpcfNotify(
NvU32 gpuInstance,
void *pArgs
)
{
OBJGPU *pGpu = gpumgrGetGpu(gpuInstance);

gpuNotifySubDeviceEvent(pGpu, NV2080_NOTIFIERS_NVPCF_EVENTS,
NULL, 0, 0, 0);
}

static void RmQueueNvpcfReplay(
OBJGPU *pGpu
)
{
NV_STATUS status = osQueueWorkItem(pGpu,
RmReplayNvpcfNotify,
NULL,
(OsQueueWorkItemFlags){.bLockGpuGroupSubdevice = NV_TRUE});

if (status != NV_OK)
{
nv_state_t *nv = NV_GET_NV_STATE(pGpu);
nv_priv_t *nvp = NV_GET_NV_PRIV(nv);

acquireDynamicPowerMutex(nvp);
nvp->dynamic_power.nvpcf_notify_pending = NV_TRUE;
releaseDynamicPowerMutex(nvp);

NV_PRINTF(LEVEL_ERROR,
"Failed to queue deferred NVPCF notification: 0x%x\n",
status);
}
}

/* Check under the mutex so a concurrent resume cannot race the defer. */
NvBool RmDeferNvpcfNotifyIfIdle(
nv_state_t *nv
)
{
nv_priv_t *nvp = NV_GET_NV_PRIV(nv);
NvBool bDefer;

if (nvp == NULL)
{
return NV_FALSE;
}

acquireDynamicPowerMutex(nvp);
bDefer = nvp->dynamic_power.state == NV_DYNAMIC_POWER_STATE_IDLE_INDICATED;
if (bDefer)
{
nvp->dynamic_power.nvpcf_notify_pending = NV_TRUE;
}
releaseDynamicPowerMutex(nvp);

return bDefer;
}

/*!
* @brief Timer callback to schedule a work item to remove idle hold off
* that was applied after GC6 exit.
Expand Down
15 changes: 10 additions & 5 deletions src/nvidia/arch/nvalloc/unix/src/osapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -6118,13 +6118,18 @@ void NV_API_CALL rm_acpi_nvpcf_notify(
if (pGpu != NULL)
{
nv_state_t *nv = NV_GET_NV_STATE(pGpu);
if ((rmStatus = os_ref_dynamic_power(nv, NV_DYNAMIC_PM_FINE)) ==
NV_OK)

/*
* NVPCF events carry no payload, so coalesce them while suspended
* and replay one after resume.
*/
if (!RmDeferNvpcfNotifyIfIdle(nv) &&
(os_ref_dynamic_power(nv, NV_DYNAMIC_PM_FINE) == NV_OK))
{
gpuNotifySubDeviceEvent(pGpu, NV2080_NOTIFIERS_NVPCF_EVENTS,
NULL, 0, 0, 0);
gpuNotifySubDeviceEvent(pGpu, NV2080_NOTIFIERS_NVPCF_EVENTS,
NULL, 0, 0, 0);
os_unref_dynamic_power(nv, NV_DYNAMIC_PM_FINE);
}
os_unref_dynamic_power(nv, NV_DYNAMIC_PM_FINE);
}
rmapiLockRelease();
}
Expand Down