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
13 changes: 13 additions & 0 deletions kernel-open/common/inc/nvkms-kapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -1675,6 +1675,19 @@ struct NvKmsKapiFunctionsTable {
struct NvKmsKapiDevice *device,
const NvU32 head,
struct NvKmsKapiVblankIntrCallback *pCallback);

/*
* Return NV_TRUE when RM reports that the device requires recovery. Query
* failures other than an unsupported command are treated as requiring
* recovery so that teardown does not submit more display methods.
*/
NvBool (*deviceNeedsRecovery)(struct NvKmsKapiDevice *device);

/*
* Disable console restoration and release modeset ownership without
* submitting display methods to a device that requires recovery.
*/
NvBool (*prepareForRecovery)(struct NvKmsKapiDevice *device);
};

/** @} */
Expand Down
26 changes: 21 additions & 5 deletions kernel-open/nvidia-drm/nvidia-drm-drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -898,6 +898,7 @@ static int nv_drm_dev_load(struct drm_device *dev)
static void nv_drm_dev_unload(struct drm_device *dev)
{
struct NvKmsKapiDevice *pDevice = NULL;
NvBool recoveryTeardown;

struct nv_drm_device *nv_dev = to_nv_device(dev);

Expand All @@ -907,23 +908,38 @@ static void nv_drm_dev_unload(struct drm_device *dev)
return;
}

recoveryTeardown = nvKms->deviceNeedsRecovery(nv_dev->pDevice);

if (recoveryTeardown) {
NV_DRM_DEV_LOG_WARN(
nv_dev,
"Using recovery-safe teardown; skipping atomic display shutdown and console restore");
}

/* Release modeset ownership if fbdev is enabled */

#if defined(NV_DRM_FBDEV_AVAILABLE)
if (nv_dev->hasFramebufferConsole) {
if (nv_dev->hasFramebufferConsole && !recoveryTeardown) {
drm_atomic_helper_shutdown(dev);
nvKms->releaseOwnership(nv_dev->pDevice);
}
#endif

cancel_delayed_work_sync(&nv_dev->hotplug_event_work);
/* Stop new event work before tearing down the NVKMS device. */
mutex_lock(&nv_dev->lock);
atomic_set(&nv_dev->enable_event_handling, false);
mutex_unlock(&nv_dev->lock);
cancel_delayed_work_sync(&nv_dev->hotplug_event_work);

WARN_ON(nv_dev->subOwnershipGranted);
if (recoveryTeardown &&
!nvKms->prepareForRecovery(nv_dev->pDevice)) {
NV_DRM_DEV_LOG_ERR(
nv_dev, "Failed to prepare NVKMS for recovery-safe teardown");
}

/* Disable event handling */
mutex_lock(&nv_dev->lock);

atomic_set(&nv_dev->enable_event_handling, false);
WARN_ON(nv_dev->subOwnershipGranted);

/* Clean up output polling */

Expand Down
5 changes: 4 additions & 1 deletion src/common/unix/nvidia-3d/interface/nvidia-3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,10 @@ void nv3dFreeChannelObject(
*/
NvBool nv3dAllocChannelSurface(Nv3dChannelPtr p3dChannel);

void nv3dFreeChannelSurface(Nv3dChannelPtr p3dChannel);
/* skipChannelIdle is only safe when the channel cannot make progress. */
void nv3dFreeChannelSurface(
Nv3dChannelPtr p3dChannel,
NvBool skipChannelIdle);


/*
Expand Down
8 changes: 6 additions & 2 deletions src/common/unix/nvidia-3d/src/nvidia-3d-surface.c
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,9 @@ NvBool nv3dAllocChannelSurface(Nv3dChannelPtr p3dChannel)
return TRUE;
}

void nv3dFreeChannelSurface(Nv3dChannelPtr p3dChannel)
void nv3dFreeChannelSurface(
Nv3dChannelPtr p3dChannel,
NvBool skipChannelIdle)
{
if (p3dChannel->p3dDevice == NULL) {
return;
Expand All @@ -201,7 +203,9 @@ void nv3dFreeChannelSurface(Nv3dChannelPtr p3dChannel)
* that any methods in the channel that might reference the
* gpuAddress have idled before we unmap the address.
*/
nvPushIdleChannel(p3dChannel->pPushChannel);
if (!skipChannelIdle) {
nvPushIdleChannel(p3dChannel->pPushChannel);
}

UnmapSurface(p3dChannel,
p3dChannel->surface.gpuAddress);
Expand Down
2 changes: 2 additions & 0 deletions src/nvidia-modeset/include/nvkms-headsurface-config.h
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,8 @@ void nvHsConfigFreeResources(
NVDevEvoRec *pDevEvo,
NVHsConfig *pHsConfig);

void nvHsConfigFreeDeviceResourcesForRecovery(NVDevEvoPtr pDevEvo);

void nvHsConfigStop(
NVDevEvoPtr pDevEvo,
const NVHsConfig *pHsConfig);
Expand Down
6 changes: 6 additions & 0 deletions src/nvidia-modeset/include/nvkms-types.h
Original file line number Diff line number Diff line change
Expand Up @@ -1121,6 +1121,12 @@ typedef struct _NVEvoDevRec {
* functions that use it.
*/
NvBool skipConsoleRestore : 1;
/*
* Indicates that the GPU requires recovery and teardown must not submit
* display methods or ask RM to restore the console. Unlike
* skipConsoleRestore, this remains set until the device is freed.
*/
NvBool skipConsoleRestoreOnTeardown : 1;
/*
* Indicates that hotplug events that occur while NVKMS is the modeset owner
* should trigger console restore modesets.
Expand Down
22 changes: 22 additions & 0 deletions src/nvidia-modeset/interface/nvkms-api.h
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ enum NvKmsIoctlCommand {
NVKMS_IOCTL_FRAMEBUFFER_CONSOLE_DISABLED,
NVKMS_IOCTL_REGISTER_VBLANK_INTR_CALLBACK,
NVKMS_IOCTL_UNREGISTER_VBLANK_INTR_CALLBACK,
NVKMS_IOCTL_PREPARE_FOR_RECOVERY,
};


Expand Down Expand Up @@ -4337,6 +4338,27 @@ struct NvKmsFramebufferConsoleDisabledParams {
struct NvKmsFramebufferConsoleDisabledReply reply;
};

/*
* NVKMS_IOCTL_PREPARE_FOR_RECOVERY
*
* Prepare an NVKMS device for teardown after the GPU has stopped responding.
* Console restore is disabled because it requires submitting display methods
* to the failed GPU. This IOCTL can only be used by kernel-mode clients.
*/

struct NvKmsPrepareForRecoveryRequest {
NvKmsDeviceHandle deviceHandle;
};

struct NvKmsPrepareForRecoveryReply {
NvU32 padding;
};

struct NvKmsPrepareForRecoveryParams {
struct NvKmsPrepareForRecoveryRequest request;
struct NvKmsPrepareForRecoveryReply reply;
};

/*!
* NVKMS_IOCTL_REGISTER_VBLANK_INTR_CALLBACK:
*
Expand Down
13 changes: 13 additions & 0 deletions src/nvidia-modeset/kapi/interface/nvkms-kapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -1675,6 +1675,19 @@ struct NvKmsKapiFunctionsTable {
struct NvKmsKapiDevice *device,
const NvU32 head,
struct NvKmsKapiVblankIntrCallback *pCallback);

/*
* Return NV_TRUE when RM reports that the device requires recovery. Query
* failures other than an unsupported command are treated as requiring
* recovery so that teardown does not submit more display methods.
*/
NvBool (*deviceNeedsRecovery)(struct NvKmsKapiDevice *device);

/*
* Disable console restoration and release modeset ownership without
* submitting display methods to a device that requires recovery.
*/
NvBool (*prepareForRecovery)(struct NvKmsKapiDevice *device);
};

/** @} */
Expand Down
65 changes: 65 additions & 0 deletions src/nvidia-modeset/kapi/src/nvkms-kapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -416,11 +416,62 @@ static NvBool RmAllocateDevice(struct NvKmsKapiDevice *device)
return NV_FALSE;
}

static NvBool DeviceNeedsRecovery(struct NvKmsKapiDevice *device)
{
NV2080_CTRL_GPU_GET_RECOVERY_ACTION_PARAMS params = { };
NvU32 ret;

if (device->hRmSubDevice == 0x0) {
return NV_TRUE;
}

ret = nvRmApiControl(device->hRmClient,
device->hRmSubDevice,
NV2080_CTRL_CMD_GPU_GET_RECOVERY_ACTION,
&params,
sizeof(params));

if (ret == NVOS_STATUS_SUCCESS) {
return params.action != NV2080_CTRL_GPU_RECOVERY_ACTION_NONE;
}

if (ret == NV_ERR_NOT_SUPPORTED) {
return NV_FALSE;
}

nvKmsKapiLogDeviceDebug(
device,
"Failed to query GPU recovery action (status 0x%08x); using recovery teardown",
ret);

return NV_TRUE;
}

static NvBool PrepareForRecovery(struct NvKmsKapiDevice *device)
{
struct NvKmsPrepareForRecoveryParams params = { };

if (device->hKmsDevice == 0x0) {
return NV_TRUE;
}

params.request.deviceHandle = device->hKmsDevice;

return nvkms_ioctl_from_kapi(device->pKmsOpen,
NVKMS_IOCTL_PREPARE_FOR_RECOVERY,
&params, sizeof(params));
}

/*
* Helper function to free NVKMS objects allocated for NvKmsKapiDevice.
*/
static void KmsFreeDevice(struct NvKmsKapiDevice *device)
{
if (DeviceNeedsRecovery(device) && !PrepareForRecovery(device)) {
nvKmsKapiLogDeviceDebug(
device, "Failed to prepare NVKMS for GPU recovery");
}

/* Free notifier and semaphore memory */

nvKmsKapiFreeNisoSurface(device, &device->semaphore);
Expand Down Expand Up @@ -622,6 +673,10 @@ static NvBool KmsAllocateDevice(struct NvKmsKapiDevice *device)

static void FreeDevice(struct NvKmsKapiDevice *device)
{
if (device == NULL) {
return;
}

/* Free NVKMS objects allocated for NvKmsKapiDevice */

KmsFreeDevice(device);
Expand Down Expand Up @@ -1012,6 +1067,14 @@ static void ReleaseOwnership(struct NvKmsKapiDevice *device)
return;
}

if (DeviceNeedsRecovery(device)) {
if (!PrepareForRecovery(device)) {
nvKmsKapiLogDeviceDebug(
device, "Failed to prepare NVKMS for GPU recovery");
}
return;
}

paramsRelease.request.deviceHandle = device->hKmsDevice;

nvkms_ioctl_from_kapi(device->pKmsOpen,
Expand Down Expand Up @@ -4206,6 +4269,8 @@ NvBool nvKmsKapiGetFunctionsTableInternal

funcsTable->registerVblankIntrCallback = RegisterVblankIntrCallback;
funcsTable->unregisterVblankIntrCallback = UnregisterVblankIntrCallback;
funcsTable->deviceNeedsRecovery = DeviceNeedsRecovery;
funcsTable->prepareForRecovery = PrepareForRecovery;

return NV_TRUE;
}
Expand Down
4 changes: 3 additions & 1 deletion src/nvidia-modeset/src/dp/nvdp-connector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -922,7 +922,9 @@ void nvDPPause(NVDPLibConnectorPtr pNVDpLibConnector)
return;
}

if (pDevEvo->skipConsoleRestore && pNVDpLibConnector->headMask != 0) {
if (pDevEvo->skipConsoleRestore &&
!pDevEvo->skipConsoleRestoreOnTeardown &&
pNVDpLibConnector->headMask != 0) {
/* Clear vbios DisplayPort RAD scratch registers, see bug 200471345 */

nvAssert(nvPopCount32(pNVDpLibConnector->headMask) == 1);
Expand Down
16 changes: 13 additions & 3 deletions src/nvidia-modeset/src/nvkms-console-restore.c
Original file line number Diff line number Diff line change
Expand Up @@ -758,12 +758,22 @@ NvBool nvEvoRestoreConsole(NVDevEvoPtr pDevEvo, const NvBool allowMST)
NvBool ret = FALSE;
NvU32 dispIndex;
NVDispEvoPtr pDispEvo;
const NVEvoApiHandlesRec *pOpenDevSurfaceHandles =
const NVEvoApiHandlesRec *pOpenDevSurfaceHandles;
NVSurfaceEvoPtr pSurfaceEvo;
struct NvKmsSetModeParams *params;

if (pDevEvo->skipConsoleRestoreOnTeardown) {
pDevEvo->skipConsoleRestore = TRUE;
nvkms_free_timer(pDevEvo->consoleRestoreTimer);
pDevEvo->consoleRestoreTimer = NULL;
return TRUE;
}

pOpenDevSurfaceHandles =
nvGetSurfaceHandlesFromOpenDevConst(pDevEvo->pNvKmsOpenDev);
NVSurfaceEvoPtr pSurfaceEvo =
pSurfaceEvo =
nvEvoGetPointerFromApiHandle(pOpenDevSurfaceHandles,
pDevEvo->fbConsoleSurfaceHandle);
struct NvKmsSetModeParams *params;

/*
* If this function fails to restore a console then NVKMS frees
Expand Down
6 changes: 4 additions & 2 deletions src/nvidia-modeset/src/nvkms-difr.c
Original file line number Diff line number Diff line change
Expand Up @@ -239,8 +239,10 @@ void nvDIFRFree(NVDIFRStateEvoPtr pDifr)
/* Cancel pending idle timer. */
nvkms_free_timer(pDifr->idleTimer);

/* Leave DIFR enabled (default state). */
SetDisabledState(pDifr, FALSE);
/* Leave DIFR enabled (default state) unless the GPU requires recovery. */
if (!pDifr->pDevEvo->skipConsoleRestoreOnTeardown) {
SetDisabledState(pDifr, FALSE);
}

/* Free resources. */
FreeDIFRCopyEngine(pDifr);
Expand Down
26 changes: 18 additions & 8 deletions src/nvidia-modeset/src/nvkms-evo.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
#include "nvkms-rmapi.h"
#include "nvkms-surface.h"
#include "nvkms-headsurface.h"
#include "nvkms-headsurface-config.h"
#include "nvkms-difr.h"
#include "nvkms-vrr.h"
#include "nvkms-ioctl.h"
Expand Down Expand Up @@ -5679,17 +5680,23 @@ void nvFreeCoreChannelEvo(NVDevEvoPtr pDevEvo)
nvFreeUnixRmHandle(&pDevEvo->handleAllocator, pDevEvo->displayHandle);
pDevEvo->displayHandle = 0;

if (!pDevEvo->skipConsoleRestore) {
nvRmVTSwitch(pDevEvo,
NV0080_CTRL_OS_UNIX_VT_SWITCH_CMD_RESTORE_VT_STATE);
} else {
nvRmVTSwitch(pDevEvo,
NV0080_CTRL_OS_UNIX_VT_SWITCH_CMD_CONSOLE_RESTORED);
if (!pDevEvo->skipConsoleRestoreOnTeardown) {
if (!pDevEvo->skipConsoleRestore) {
nvRmVTSwitch(
pDevEvo,
NV0080_CTRL_OS_UNIX_VT_SWITCH_CMD_RESTORE_VT_STATE);
} else {
nvRmVTSwitch(
pDevEvo,
NV0080_CTRL_OS_UNIX_VT_SWITCH_CMD_CONSOLE_RESTORED);
}
}
}

// No longer possible that NVKMS is driving any displays, allow GC6.
nvRmSetGc6Allowed(pDevEvo, TRUE);
if (!pDevEvo->skipConsoleRestoreOnTeardown) {
nvRmSetGc6Allowed(pDevEvo, TRUE);
}

nvFree(pDevEvo->gpus);
pDevEvo->gpus = NULL;
Expand Down Expand Up @@ -8808,6 +8815,10 @@ NvBool nvFreeDevEvo(NVDevEvoPtr pDevEvo)
pDevEvo->fbConsoleSurfaceHandle = 0;
}

if (pDevEvo->skipConsoleRestoreOnTeardown) {
nvHsConfigFreeDeviceResourcesForRecovery(pDevEvo);
}

nvFreeLutSurfacesEvo(pDevEvo);

nvFreeCoreChannelEvo(pDevEvo);
Expand Down Expand Up @@ -9913,4 +9924,3 @@ NvBool nvEvoIsConsoleActive(const NVDevEvoRec *pDevEvo)

return FALSE;
}

4 changes: 4 additions & 0 deletions src/nvidia-modeset/src/nvkms-flip.c
Original file line number Diff line number Diff line change
Expand Up @@ -1148,6 +1148,10 @@ void nvEvoClearSurfaceUsage(NVDevEvoRec *pDevEvo,
{
NvU32 head;

if (pDevEvo->skipConsoleRestoreOnTeardown) {
return;
}

/*
* If the core channel is no longer allocated, we don't need to
* clear usage/sync. This assumes the channels are allocated/deallocated
Expand Down
Loading