Skip to content
Open
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
52 changes: 37 additions & 15 deletions src/nvidia-modeset/src/nvkms-modeset.c
Original file line number Diff line number Diff line change
Expand Up @@ -2414,9 +2414,30 @@ static NvBool IsCurrentMultiTileConfigOneApiHeadIncompatible(
&pDispEvo->headState[head].multiTileConfig;
const NvU32 tilesMask = pMultiTileConfig->tilesMask;
NvU32 phywinsMask = 0x0;
NvU32 proposedPhywinsMask = 0x0;

for (NvU32 layer = 0; layer < pDevEvo->head[head].numLayers; layer++) {
phywinsMask |= pMultiTileConfig->phywinsMask[layer];
const NvU32 currentMask = pMultiTileConfig->phywinsMask[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 ((currentMask == 0) != (proposedMask == 0)) {
return TRUE;
}

/* Check both directions against earlier layers on this head. */
if (((currentMask & proposedPhywinsMask) != 0x0) ||
((proposedMask & phywinsMask) != 0x0)) {
return TRUE;
}

phywinsMask |= currentMask;
proposedPhywinsMask |= proposedMask;
}

for (NvU32 tmpHead = 0; tmpHead < pDevEvo->numHeads; tmpHead++) {
Expand Down Expand Up @@ -3472,19 +3493,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 +3515,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 Expand Up @@ -4674,4 +4697,3 @@ void nvApiHeadGetScanLine(const NVDispEvoRec *pDispEvo,
pDispEvo->pDevEvo->hal->GetScanLine(pDispEvo, head, pScanLine,
pInBlankingPeriod);
}