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
138 changes: 127 additions & 11 deletions src/nvidia-modeset/src/nvkms-evo4.c
Original file line number Diff line number Diff line change
Expand Up @@ -2026,6 +2026,7 @@ static void UnassignExtraOrIncompatibleTiles(
const NVDispEvoRec *pDispEvo,
NVHwHeadMultiTileConfigRec *pMultiTileConfig,
const NVHwModeTimingsEvo *pTimings,
const struct NvKmsUsageBounds *pUsage,
const NvU32 numRequiredTiles)
{
const NVDevEvoRec *pDevEvo = pDispEvo->pDevEvo;
Expand Down Expand Up @@ -2057,6 +2058,11 @@ static void UnassignExtraOrIncompatibleTiles(
layer < ARRAY_LEN(pMultiTileConfig->phywinsMask); layer++) {
NvU32 numReusedPhywins = 0;
NvU32 phywin;

/* Do not retain physical windows for layers excluded by IMP. */
if (!pUsage->layer[layer].usable) {
continue;
}
FOR_EACH_INDEX_IN_MASK(32, phywin,
pMultiTileConfig->phywinsMask[layer]) {
nvAssert(phywin < pDevEvo->numHwPhywins);
Expand Down Expand Up @@ -2130,6 +2136,7 @@ static NvBool
AssignNewPhywinsIfNeeded(const NVDispEvoRec *pDispEvo,
NVHwHeadMultiTileConfigRec *pMultiTileConfig,
const NvU32 head,
const struct NvKmsUsageBounds *pUsage,
NvU32 *pFreePhywinsMask)
{
const NVDevEvoRec *pDevEvo = pDispEvo->pDevEvo;
Expand All @@ -2138,6 +2145,12 @@ AssignNewPhywinsIfNeeded(const NVDispEvoRec *pDispEvo,

for (NvU32 layer = 0; layer < pDevEvo->head[head].numLayers; layer++) {
NvU32 phywin;

if (!pUsage->layer[layer].usable) {
nvAssert(outMultiTileConfig.phywinsMask[layer] == 0);
continue;
}

FOR_EACH_INDEX_IN_MASK(32, phywin, outFreePhywinsMask) {
nvAssert(phywin < pDevEvo->numHwPhywins);

Expand Down Expand Up @@ -2165,6 +2178,7 @@ static NvBool AssignNewTilesToHeadIfNeeded(
NVHwHeadMultiTileConfigRec *pMultiTileConfig,
const NvU32 head,
const NVHwModeTimingsEvo *pTimings,
const struct NvKmsUsageBounds *pUsage,
NvU32 numRequiredTiles,
NvU32 *pFreeTilesMask,
NvU32 *pFreePhywinsMask)
Expand All @@ -2179,21 +2193,19 @@ static NvBool AssignNewTilesToHeadIfNeeded(
nvAssert(nvPopCount32(outMultiTileConfig.tilesMask) <= numRequiredTiles);
nvAssert((outMultiTileConfig.tilesMask & outFreeTilesMask) == 0x0);

/* Return early if we already assigned sufficient tiles. */
if (deltaNumRequiredTiles == 0) {
return TRUE;
if (deltaNumRequiredTiles != 0) {
outMultiTileConfig.tilesMask |=
GetFreeTiles(pDispEvo, deltaNumRequiredTiles, requiredTileType,
&outFreeTilesMask);
}

outMultiTileConfig.tilesMask |=
GetFreeTiles(pDispEvo, deltaNumRequiredTiles, requiredTileType,
&outFreeTilesMask);

if (nvPopCount32(outMultiTileConfig.tilesMask) < numRequiredTiles) {
return FALSE;
}

/* Layer usage can change even when the tile count stays the same. */
if (!AssignNewPhywinsIfNeeded(pDispEvo, &outMultiTileConfig, head,
&outFreePhywinsMask)) {
pUsage, &outFreePhywinsMask)) {
return FALSE;
}

Expand Down Expand Up @@ -2310,6 +2322,7 @@ AssignNewTilesToHeadsIfNeeded(
pOutputMultiTileConfig,
head,
pTimings,
pInput->head[head].pUsage,
numRequiredTiles[head],
&freeTilesMask,
&freePhywinsMask)) {
Expand All @@ -2328,7 +2341,18 @@ AssignNewTilesToHeadsIfNeeded(
pOutput,
&freeTilesMask,
&freePhywinsMask);
break;

/* Retry the failed head with the reclaimed resources. */
if (AssignNewTilesToHeadIfNeeded(pDispEvo,
pOutputMultiTileConfig,
head,
pTimings,
pInput->head[head].pUsage,
numRequiredTiles[head],
&freeTilesMask,
&freePhywinsMask)) {
continue;
}
}

return FALSE;
Expand All @@ -2348,7 +2372,8 @@ EvoAssignHwHeadMultiTileConfigDispOutputCA(
{
const NVDevEvoRec *pDevEvo = pDispEvo->pDevEvo;
NvU32 freeTilesMask = NVBIT(pDevEvo->numHwTiles) - 1;
NvU32 freePhywinsMask = NVBIT(pDevEvo->numHwPhywins) - 1;
/* The capability format allows 32 windows; avoid a 32-bit shift by 32. */
NvU32 freePhywinsMask = (NvU32)(NVBIT64(pDevEvo->numHwPhywins) - 1);

for (NvU32 head = 0; head < pDevEvo->numHeads; head++) {
if (pInput->head[head].pTimings == NULL) {
Expand Down Expand Up @@ -2377,7 +2402,18 @@ EvoAssignHwHeadMultiTileConfigDispOutputCA(
UnassignExtraOrIncompatibleTiles(pDispEvo,
&pOutput->head[head].multiTileConfig,
pInput->head[head].pTimings,
pInput->head[head].pUsage,
numRequiredTiles[head]);
} else {
/* A flip cannot bind a window or grow its physical assignment. */
for (NvU32 layer = 0;
layer < pDevEvo->head[head].numLayers; layer++) {
if (pInput->head[head].pUsage->layer[layer].usable &&
nvPopCount32(pOutput->head[head].multiTileConfig.
phywinsMask[layer]) < numRequiredTiles[head]) {
return FALSE;
}
}
}

freeTilesMask &= ~pOutput->head[head].multiTileConfig.tilesMask;
Expand Down Expand Up @@ -2765,6 +2801,68 @@ static void SetTileSize(NVEvoChannel *pCoreChannel,
nvAssert(tileStart == hActive);
}

/*
* Physical window assignment changes need the same interlock handling as
* logical window assignment changes in EvoInitWindowMapping3().
*/
static void EvoTrackPhysicalWindowChangeCA(
NVDevEvoRec *pDevEvo,
const NVEvoChannel *pWindowChannel,
const NvU32 oldMask,
const NvU32 newMask,
NVEvoModesetUpdateState *pModesetUpdateState)
{
if (oldMask == newMask) {
return;
}

pModesetUpdateState->windowMappingChanged = TRUE;
nvDisableCoreInterlockUpdateState(pDevEvo,
&pModesetUpdateState->updateState,
pWindowChannel);
}

/*
* Keep the software window-to-head mapping and advertised layers unchanged.
* Hardware ownership follows the physical assignment for the current mode:
* an unusable layer has neither an owner nor physical windows. This matches
* the unassigned-window state established by overlay-off initialization.
*
* The caller has shut down heads whose layer ownership changes.
*/
static void EvoSetWindowOwnerCA(
NVDevEvoRec *pDevEvo,
const NvU32 sd,
const NVEvoChannel *pWindowChannel,
const NvU32 head,
const NvU32 phywinsMask,
NVEvoModesetUpdateState *pModesetUpdateState)
{
const NvU32 win = NV_EVO_CHANNEL_MASK_WINDOW_NUMBER(
pWindowChannel->channelMask);
const void *pCoreDma = pDevEvo->pSubDevices[sd]->pCoreDma;
const NvU32 oldControl =
nvDmaLoadPioMethod(pCoreDma, NVCA7D_WINDOW_SET_CONTROL(win));
const NvU32 oldOwner = DRF_VAL(CA7D, _WINDOW_SET_CONTROL, _OWNER, oldControl);
const NvU32 owner = (phywinsMask != 0) ? head :
NVCA7D_WINDOW_SET_CONTROL_OWNER_NONE;

if (oldOwner != owner) {
pModesetUpdateState->windowMappingChanged = TRUE;
nvDisableCoreInterlockUpdateState(pDevEvo,
&pModesetUpdateState->updateState,
pWindowChannel);
}

/*
* Initialization may have queued a default binding that is not yet visible
* in PIO. Write the final owner even when the cached owner already matches.
*/
nvDmaSetStartEvoMethod(pDevEvo->core, NVCA7D_WINDOW_SET_CONTROL(win), 1);
nvDmaSetEvoMethodData(pDevEvo->core,
FLD_SET_DRF_NUM(CA7D, _WINDOW_SET_CONTROL, _OWNER, owner, oldControl));
}

static void EvoSetMultiTileConfigCA(const NVDispEvoRec *pDispEvo,
const NvU32 head,
const NVHwModeTimingsEvo *pTimings,
Expand All @@ -2787,7 +2885,25 @@ static void EvoSetMultiTileConfigCA(const NVDispEvoRec *pDispEvo,
const NvU32 win = NV_EVO_CHANNEL_MASK_WINDOW_NUMBER(
pWindowChannel->channelMask);

nvAssert(nvPopCount32(pConfig->tilesMask) == nvPopCount32(phywinsMask));
const void *pCoreDma =
pDevEvo->pSubDevices[pDispEvo->displayOwner]->pCoreDma;
const NvU32 oldPhywinsMask =
nvDmaLoadPioMethod(pCoreDma, NVCA7D_WINDOW_SET_PHYSICAL(win));

EvoTrackPhysicalWindowChangeCA(pDevEvo, pWindowChannel,
oldPhywinsMask, phywinsMask,
pModesetUpdateState);

/* Retain ownership during shutdown; change it in the next modeset. */
if (pTimings != NULL) {
EvoSetWindowOwnerCA(pDevEvo, pDispEvo->displayOwner,
pWindowChannel, head, phywinsMask,
pModesetUpdateState);
}

/* Unusable layers have no physical windows assigned. */
nvAssert((phywinsMask == 0) ||
(nvPopCount32(pConfig->tilesMask) == nvPopCount32(phywinsMask)));

nvDmaSetStartEvoMethod(pCoreChannel,
NVCA7D_WINDOW_SET_PHYSICAL(win), 1);
Expand Down
53 changes: 40 additions & 13 deletions src/nvidia-modeset/src/nvkms-modeset.c
Original file line number Diff line number Diff line change
Expand Up @@ -2416,9 +2416,34 @@ static NvBool IsCurrentMultiTileConfigOneApiHeadIncompatible(
NvU32 phywinsMask = 0x0;

for (NvU32 layer = 0; layer < pDevEvo->head[head].numLayers; layer++) {
const NvU32 proposedMask =
pProposedDisp->head[head].multiTileConfig.phywinsMask[layer];

/*
* Adding or removing a layer's physical assignment also binds or
* unbinds its window channel. Shut the head down before changing
* that ownership, even if no resource moves to another window.
*/
if ((pMultiTileConfig->phywinsMask[layer] == 0) !=
(proposedMask == 0)) {
return TRUE;
}
phywinsMask |= pMultiTileConfig->phywinsMask[layer];
}

/* Physical windows may also move between layers on the same head. */
for (NvU32 layer = 0; layer < pDevEvo->head[head].numLayers; layer++) {
for (NvU32 otherLayer = 0;
otherLayer < pDevEvo->head[head].numLayers; otherLayer++) {
if ((layer != otherLayer) &&
((pMultiTileConfig->phywinsMask[layer] &
pProposedDisp->head[head].multiTileConfig.
phywinsMask[otherLayer]) != 0x0)) {
return TRUE;
}
}
}

for (NvU32 tmpHead = 0; tmpHead < pDevEvo->numHeads; tmpHead++) {
const NVHwHeadMultiTileConfigRec *pTmpMultiTileConfig =
&pProposedDisp->head[tmpHead].multiTileConfig;
Expand Down Expand Up @@ -3472,19 +3497,7 @@ KickoffProposedModeSetHwState(
{
NVDevEvoRec *pDevEvo = pDispEvo->pDevEvo;
NVEvoModesetUpdateState *pModesetUpdateState = &pWorkArea->modesetUpdateState;
/*
* If there is a change in window ownership, decouple window channel flips
* and the core channel update that performs a modeset.
*
* This allows window channel flips to be instead interlocked with the core
* channel update that sets the window usage bounds, avoiding window
* invalid usage exceptions.
*
* See comment about NVDisplay error code 37, in
* function EvoInitWindowMapping3().
*/
const NvBool decoupleFlipUpdates =
pModesetUpdateState->windowMappingChanged;
NvBool decoupleFlipUpdates;

/* Send methods to shut down any other unused heads, but don't update yet. */
for (NvU32 apiHead = 0; apiHead < pDevEvo->numApiHeads; apiHead++) {
Expand All @@ -3506,6 +3519,20 @@ KickoffProposedModeSetHwState(
bypassComposition);
}

/*
* If window ownership or physical assignments change, decouple window
* channel flips from the core channel update that performs a modeset.
* Check after PreUpdate, which may change physical assignments on Blackwell.
*
* This allows window channel flips to be instead interlocked with the core
* channel update that sets the window usage bounds, avoiding window
* invalid usage exceptions.
*
* See comment about NVDisplay error code 37, in
* function EvoInitWindowMapping3().
*/
decoupleFlipUpdates = pModesetUpdateState->windowMappingChanged;

if (!decoupleFlipUpdates) {
/* Merge modeset and flip state updates together */
ApplyProposedModeSetStateOneDispFlip(
Expand Down