545.23.06

This commit is contained in:
Andy Ritger
2023-10-17 09:25:29 -07:00
parent f59818b751
commit b5bf85a8e3
917 changed files with 132480 additions and 110015 deletions

View File

@@ -174,4 +174,41 @@ void
nvKmsKapiFreeChannelEvent(struct NvKmsKapiDevice *device,
struct NvKmsKapiChannelEvent *cb);
struct NvKmsKapiSemaphoreSurface*
nvKmsKapiImportSemaphoreSurface(struct NvKmsKapiDevice *device,
NvU64 nvKmsParamsUser,
NvU64 nvKmsParamsSize,
void **pSemaphoreMap,
void **pMaxSubmittedMap);
void
nvKmsKapiFreeSemaphoreSurface(struct NvKmsKapiDevice *device,
struct NvKmsKapiSemaphoreSurface *ss);
NvKmsKapiRegisterWaiterResult
nvKmsKapiRegisterSemaphoreSurfaceCallback(
struct NvKmsKapiDevice *device,
struct NvKmsKapiSemaphoreSurface *semaphoreSurface,
NvKmsSemaphoreSurfaceCallbackProc *pCallback,
void *pData,
NvU64 index,
NvU64 wait_value,
NvU64 new_value,
struct NvKmsKapiSemaphoreSurfaceCallback **pCallbackHandle);
NvBool
nvKmsKapiUnregisterSemaphoreSurfaceCallback(
struct NvKmsKapiDevice *device,
struct NvKmsKapiSemaphoreSurface *semaphoreSurface,
NvU64 index,
NvU64 wait_value,
struct NvKmsKapiSemaphoreSurfaceCallback *callbackHandle);
NvBool
nvKmsKapiSetSemaphoreSurfaceValue(
struct NvKmsKapiDevice *device,
struct NvKmsKapiSemaphoreSurface *semaphoreSurface,
NvU64 index,
NvU64 new_value);
#endif /* __NVKMS_KAPI_INTERNAL_H__ */

View File

@@ -58,4 +58,10 @@ struct NvKmsKapiPrivExportMemoryParams {
int memFd;
};
struct NvKmsKapiPrivImportSemaphoreSurfaceParams {
NvHandle hClient;
NvHandle hSemaphoreSurface;
NvU64 semaphoreSurfaceSize;
};
#endif /* !defined(__NVKMS_KAPI_PRIVATE_H__) */

View File

@@ -49,6 +49,8 @@ struct NvKmsKapiDevice;
struct NvKmsKapiMemory;
struct NvKmsKapiSurface;
struct NvKmsKapiChannelEvent;
struct NvKmsKapiSemaphoreSurface;
struct NvKmsKapiSemaphoreSurfaceCallback;
typedef NvU32 NvKmsKapiConnector;
typedef NvU32 NvKmsKapiDisplay;
@@ -67,6 +69,14 @@ typedef NvU32 NvKmsKapiDisplay;
*/
typedef void NvKmsChannelEventProc(void *dataPtr, NvU32 dataU32);
/*
* Note: Same as above, this function must not call back into NVKMS-KAPI, nor
* directly into RM. Doing so could cause deadlocks given the notification
* function will most likely be called from within RM's interrupt handler
* callchain.
*/
typedef void NvKmsSemaphoreSurfaceCallbackProc(void *pData);
/** @} */
/**
@@ -126,6 +136,11 @@ struct NvKmsKapiDeviceResourcesInfo {
NvU32 validCursorCompositionModes;
NvU64 supportedCursorSurfaceMemoryFormats;
struct {
NvU64 maxSubmittedOffset;
NvU64 stride;
} semsurf;
struct {
NvU16 validRRTransforms;
NvU32 validCompositionModes;
@@ -218,8 +233,10 @@ struct NvKmsKapiLayerConfig {
struct NvKmsRRParams rrParams;
struct NvKmsKapiSyncpt syncptParams;
struct NvKmsHDRStaticMetadata hdrMetadata;
NvBool hdrMetadataSpecified;
struct {
struct NvKmsHDRStaticMetadata val;
NvBool enabled;
} hdrMetadata;
enum NvKmsOutputTf tf;
@@ -233,16 +250,21 @@ struct NvKmsKapiLayerConfig {
NvU16 dstWidth, dstHeight;
enum NvKmsInputColorSpace inputColorSpace;
struct NvKmsCscMatrix csc;
NvBool cscUseMain;
};
struct NvKmsKapiLayerRequestedConfig {
struct NvKmsKapiLayerConfig config;
struct {
NvBool surfaceChanged : 1;
NvBool srcXYChanged : 1;
NvBool srcWHChanged : 1;
NvBool dstXYChanged : 1;
NvBool dstWHChanged : 1;
NvBool surfaceChanged : 1;
NvBool srcXYChanged : 1;
NvBool srcWHChanged : 1;
NvBool dstXYChanged : 1;
NvBool dstWHChanged : 1;
NvBool cscChanged : 1;
NvBool tfChanged : 1;
NvBool hdrMetadataChanged : 1;
} flags;
};
@@ -286,14 +308,41 @@ struct NvKmsKapiHeadModeSetConfig {
struct NvKmsKapiDisplayMode mode;
NvBool vrrEnabled;
struct {
NvBool enabled;
enum NvKmsInfoFrameEOTF eotf;
struct NvKmsHDRStaticMetadata staticMetadata;
} hdrInfoFrame;
enum NvKmsOutputColorimetry colorimetry;
struct {
struct {
NvBool specified;
NvU32 depth;
NvU32 start;
NvU32 end;
struct NvKmsLutRamps *pRamps;
} input;
struct {
NvBool specified;
NvBool enabled;
struct NvKmsLutRamps *pRamps;
} output;
} lut;
};
struct NvKmsKapiHeadRequestedConfig {
struct NvKmsKapiHeadModeSetConfig modeSetConfig;
struct {
NvBool activeChanged : 1;
NvBool displaysChanged : 1;
NvBool modeChanged : 1;
NvBool activeChanged : 1;
NvBool displaysChanged : 1;
NvBool modeChanged : 1;
NvBool hdrInfoFrameChanged : 1;
NvBool colorimetryChanged : 1;
NvBool lutChanged : 1;
} flags;
struct NvKmsKapiCursorRequestedConfig cursorRequestedConfig;
@@ -318,6 +367,7 @@ struct NvKmsKapiHeadReplyConfig {
};
struct NvKmsKapiModeSetReplyConfig {
enum NvKmsFlipResult flipResult;
struct NvKmsKapiHeadReplyConfig
headReplyConfig[NVKMS_KAPI_MAX_HEADS];
};
@@ -434,6 +484,12 @@ enum NvKmsKapiAllocationType {
NVKMS_KAPI_ALLOCATION_TYPE_OFFSCREEN = 2,
};
typedef enum NvKmsKapiRegisterWaiterResultRec {
NVKMS_KAPI_REG_WAITER_FAILED,
NVKMS_KAPI_REG_WAITER_SUCCESS,
NVKMS_KAPI_REG_WAITER_ALREADY_SIGNALLED,
} NvKmsKapiRegisterWaiterResult;
struct NvKmsKapiFunctionsTable {
/*!
@@ -519,8 +575,8 @@ struct NvKmsKapiFunctionsTable {
);
/*!
* Revoke permissions previously granted. Only one (dispIndex, head,
* display) is currently supported.
* Revoke modeset permissions previously granted. Only one (dispIndex,
* head, display) is currently supported.
*
* \param [in] device A device returned by allocateDevice().
*
@@ -537,6 +593,34 @@ struct NvKmsKapiFunctionsTable {
NvKmsKapiDisplay display
);
/*!
* Grant modeset sub-owner permissions to fd. This is used by clients to
* convert drm 'master' permissions into nvkms sub-owner permission.
*
* \param [in] fd fd from opening /dev/nvidia-modeset.
*
* \param [in] device A device returned by allocateDevice().
*
* \return NV_TRUE on success, NV_FALSE on failure.
*/
NvBool (*grantSubOwnership)
(
NvS32 fd,
struct NvKmsKapiDevice *device
);
/*!
* Revoke sub-owner permissions previously granted.
*
* \param [in] device A device returned by allocateDevice().
*
* \return NV_TRUE on success, NV_FALSE on failure.
*/
NvBool (*revokeSubOwnership)
(
struct NvKmsKapiDevice *device
);
/*!
* Registers for notification, via
* NvKmsKapiAllocateDeviceParams::eventCallback, of the events specified
@@ -1122,6 +1206,199 @@ struct NvKmsKapiFunctionsTable {
NvP64 dmaBuf,
NvU32 limit);
/*!
* Import a semaphore surface allocated elsewhere to NVKMS and return a
* handle to the new object.
*
* \param [in] device A device allocated using allocateDevice().
*
* \param [in] nvKmsParamsUser Userspace pointer to driver-specific
* parameters describing the semaphore
* surface being imported.
*
* \param [in] nvKmsParamsSize Size of the driver-specific parameter
* struct.
*
* \param [out] pSemaphoreMap Returns a CPU mapping of the semaphore
* surface's semaphore memory to the client.
*
* \param [out] pMaxSubmittedMap Returns a CPU mapping of the semaphore
* surface's semaphore memory to the client.
*
* \return struct NvKmsKapiSemaphoreSurface* on success, NULL on failure.
*/
struct NvKmsKapiSemaphoreSurface* (*importSemaphoreSurface)
(
struct NvKmsKapiDevice *device,
NvU64 nvKmsParamsUser,
NvU64 nvKmsParamsSize,
void **pSemaphoreMap,
void **pMaxSubmittedMap
);
/*!
* Free an imported semaphore surface.
*
* \param [in] device The device passed to
* importSemaphoreSurface() when creating
* semaphoreSurface.
*
* \param [in] semaphoreSurface A semaphore surface returned by
* importSemaphoreSurface().
*/
void (*freeSemaphoreSurface)
(
struct NvKmsKapiDevice *device,
struct NvKmsKapiSemaphoreSurface *semaphoreSurface
);
/*!
* Register a callback to be called when a semaphore reaches a value.
*
* The callback will be called when the semaphore at index in
* semaphoreSurface reaches the value wait_value. The callback will
* be called at most once and is automatically unregistered when called.
* It may also be unregistered (i.e., cancelled) explicitly using the
* unregisterSemaphoreSurfaceCallback() function. To avoid leaking the
* memory used to track the registered callback, callers must ensure one
* of these methods of unregistration is used for every successful
* callback registration that returns a non-NULL pCallbackHandle.
*
* \param [in] device The device passed to
* importSemaphoreSurface() when creating
* semaphoreSurface.
*
* \param [in] semaphoreSurface A semaphore surface returned by
* importSemaphoreSurface().
*
* \param [in] pCallback A pointer to the function to call when
* the specified value is reached. NULL
* means no callback.
*
* \param [in] pData Arbitrary data to be passed back to the
* callback as its sole parameter.
*
* \param [in] index The index of the semaphore within
* semaphoreSurface.
*
* \param [in] wait_value The value the semaphore must reach or
* exceed before the callback is called.
*
* \param [in] new_value The value the semaphore will be set to
* when it reaches or exceeds <wait_value>.
* 0 means do not update the value.
*
* \param [out] pCallbackHandle On success, the value pointed to will
* contain an opaque handle to the
* registered callback that may be used to
* cancel it if needed. Unused if pCallback
* is NULL.
*
* \return NVKMS_KAPI_REG_WAITER_SUCCESS if the waiter was registered or if
* no callback was requested and the semaphore at <index> has
* already reached or exceeded <wait_value>
*
* NVKMS_KAPI_REG_WAITER_ALREADY_SIGNALLED if a callback was
* requested and the semaphore at <index> has already reached or
* exceeded <wait_value>
*
* NVKMS_KAPI_REG_WAITER_FAILED if waiter registration failed.
*/
NvKmsKapiRegisterWaiterResult
(*registerSemaphoreSurfaceCallback)
(
struct NvKmsKapiDevice *device,
struct NvKmsKapiSemaphoreSurface *semaphoreSurface,
NvKmsSemaphoreSurfaceCallbackProc *pCallback,
void *pData,
NvU64 index,
NvU64 wait_value,
NvU64 new_value,
struct NvKmsKapiSemaphoreSurfaceCallback **pCallbackHandle
);
/*!
* Unregister a callback registered via registerSemaphoreSurfaceCallback()
*
* If the callback has not yet been called, this function will cancel the
* callback and free its associated resources.
*
* Note this function treats the callback handle as a pointer. While this
* function does not dereference that pointer itself, the underlying call
* to RM does within a properly guarded critical section that first ensures
* it is not in the process of being used within a callback. This means
* the callstack must take into consideration that pointers are not in
* general unique handles if they may have been freed, since a subsequent
* malloc could return the same pointer value at that point. This callchain
* avoids that by leveraging the behavior of the underlying RM APIs:
*
* 1) A callback handle is referenced relative to its corresponding
* (semaphore surface, index, wait_value) tuple here and within RM. It
* is not a valid handle outside of that scope.
*
* 2) A callback can not be registered against an already-reached value
* for a given semaphore surface index.
*
* 3) A given callback handle can not be registered twice against the same
* (semaphore surface, index, wait_value) tuple, so unregistration will
* never race with registration at the RM level, and would only race at
* a higher level if used incorrectly. Since this is kernel code, we
* can safely assume there won't be malicious clients purposely misuing
* the API, but the burden is placed on the caller to ensure its usage
* does not lead to races at higher levels.
*
* These factors considered together ensure any valid registered handle is
* either still in the relevant waiter list and refers to the same event/
* callback as when it was registered, or has been removed from the list
* as part of a critical section that also destroys the list itself and
* makes future lookups in that list impossible, and hence eliminates the
* chance of comparing a stale handle with a new handle of the same value
* as part of a lookup.
*
* \param [in] device The device passed to
* importSemaphoreSurface() when creating
* semaphoreSurface.
*
* \param [in] semaphoreSurface The semaphore surface passed to
* registerSemaphoreSurfaceCallback() when
* registering the callback.
*
* \param [in] index The index passed to
* registerSemaphoreSurfaceCallback() when
* registering the callback.
*
* \param [in] wait_value The wait_value passed to
* registerSemaphoreSurfaceCallback() when
* registering the callback.
*
* \param [in] callbackHandle The callback handle returned by
* registerSemaphoreSurfaceCallback().
*/
NvBool
(*unregisterSemaphoreSurfaceCallback)
(
struct NvKmsKapiDevice *device,
struct NvKmsKapiSemaphoreSurface *semaphoreSurface,
NvU64 index,
NvU64 wait_value,
struct NvKmsKapiSemaphoreSurfaceCallback *callbackHandle
);
/*!
* Update the value of a semaphore surface from the CPU.
*
* Update the semaphore value at the specified index from the CPU, then
* wake up any pending CPU waiters associated with that index that are
* waiting on it reaching a value <= the new value.
*/
NvBool
(*setSemaphoreSurfaceValue)
(
struct NvKmsKapiDevice *device,
struct NvKmsKapiSemaphoreSurface *semaphoreSurface,
NvU64 index,
NvU64 new_value
);
};
/** @} */

View File

@@ -29,7 +29,9 @@
#include "nvkms-kapi-private.h"
#include "nvkms-kapi-internal.h"
#include "class/cl0000.h"
#include "class/cl0005.h"
#include "ctrl/ctrl00da.h"
struct NvKmsKapiChannelEvent {
struct NvKmsKapiDevice *device;
@@ -168,3 +170,402 @@ fail:
nvKmsKapiFreeChannelEvent(device, cb);
return NULL;
}
struct NvKmsKapiSemaphoreSurface {
NvHandle hSemaphoreSurface;
NvHandle hSemaphoreMem;
NvHandle hMaxSubmittedMem;
};
struct NvKmsKapiSemaphoreSurface*
nvKmsKapiImportSemaphoreSurface
(
struct NvKmsKapiDevice *device,
NvU64 nvKmsParamsUser,
NvU64 nvKmsParamsSize,
void **pSemaphoreMap,
void **pMaxSubmittedMap
)
{
struct NvKmsKapiSemaphoreSurface *ss = NULL;
struct NvKmsKapiPrivImportSemaphoreSurfaceParams p, *pHeap;
NV_SEMAPHORE_SURFACE_CTRL_REF_MEMORY_PARAMS refParams = {};
NvU32 ret;
int status;
/* Verify the driver-private params size and copy it in from userspace */
if (nvKmsParamsSize != sizeof(p)) {
nvKmsKapiLogDebug(
"NVKMS semaphore surface import parameter size mismatch - expected: 0x%llx, caller specified: 0x%llx",
(NvU64)sizeof(p), nvKmsParamsSize);
goto fail;
}
/*
* Use a heap allocation as the destination pointer passed to
* nvkms_copyin; stack allocations created within core NVKMS may not
* be recognizable to the Linux kernel's CONFIG_HARDENED_USERCOPY
* checker, triggering false errors. But then save the result to a
* variable on the stack, so that we can free the heap memory
* immediately and not worry about its lifetime.
*/
pHeap = nvKmsKapiCalloc(1, sizeof(*pHeap));
if (pHeap == NULL) {
nvKmsKapiLogDebug(
"NVKMS failed to allocate semaphore surface parameter struct of size: %ld",
(long)sizeof(*pHeap));
goto fail;
}
status = nvkms_copyin(pHeap, nvKmsParamsUser, sizeof(*pHeap));
p = *pHeap;
nvKmsKapiFree(pHeap);
if (status != 0) {
nvKmsKapiLogDebug(
"NVKMS semaphore surface import parameters could not be read from userspace");
goto fail;
}
ss = nvKmsKapiCalloc(1, sizeof(*ss));
if (ss == NULL) {
nvKmsKapiLogDeviceDebug(
device,
"Failed to allocate memory for NVKMS semaphore surface while importing (0x%08x, 0x%08x)",
p.hClient, p.hSemaphoreSurface);
goto fail;
}
ret = nvRmApiDupObject2(device->hRmClient,
device->hRmSubDevice,
&ss->hSemaphoreSurface,
p.hClient,
p.hSemaphoreSurface,
0);
if (ret != NVOS_STATUS_SUCCESS) {
nvKmsKapiLogDeviceDebug(
device,
"Failed to dup RM semaphore surface object (0x%08x, 0x%08x)",
p.hClient, p.hSemaphoreSurface);
goto fail;
}
ret = nvRmApiControl(device->hRmClient,
ss->hSemaphoreSurface,
NV_SEMAPHORE_SURFACE_CTRL_CMD_REF_MEMORY,
&refParams,
sizeof(refParams));
if (ret != NVOS_STATUS_SUCCESS) {
nvKmsKapiLogDeviceDebug(
device,
"Failed to ref RM semaphore surface memory objects (0x%08x, 0x%08x)",
p.hClient, p.hSemaphoreSurface);
goto fail;
}
ss->hSemaphoreMem = refParams.hSemaphoreMem;
ss->hMaxSubmittedMem = refParams.hMaxSubmittedMem;
ret = nvRmApiMapMemory(device->hRmClient,
device->hRmDevice,
ss->hSemaphoreMem,
0,
p.semaphoreSurfaceSize,
pSemaphoreMap,
0);
if (ret != NVOS_STATUS_SUCCESS) {
nvKmsKapiLogDeviceDebug(
device,
"Failed to map RM semaphore surface semaphore memory (0x%08x, 0x%08x)",
p.hClient, p.hSemaphoreSurface);
goto fail;
}
if (ss->hMaxSubmittedMem != NV01_NULL_OBJECT) {
if (ss->hMaxSubmittedMem != ss->hSemaphoreMem) {
ret = nvRmApiMapMemory(device->hRmClient,
device->hRmDevice,
ss->hMaxSubmittedMem,
0,
p.semaphoreSurfaceSize,
pMaxSubmittedMap,
0);
if (ret != NVOS_STATUS_SUCCESS) {
nvKmsKapiLogDeviceDebug(
device,
"Failed to map RM semaphore surface max submitted memory (0x%08x, 0x%08x)",
p.hClient, p.hSemaphoreSurface);
goto fail;
}
} else {
*pMaxSubmittedMap = *pSemaphoreMap;
}
} else {
*pMaxSubmittedMap = NULL;
}
return ss;
fail:
if (ss && ss->hSemaphoreSurface) {
if ((ss->hMaxSubmittedMem != NV01_NULL_OBJECT) &&
(ss->hMaxSubmittedMem != ss->hSemaphoreMem)) {
nvRmApiFree(device->hRmClient,
device->hRmDevice,
ss->hMaxSubmittedMem);
}
if (ss->hSemaphoreMem != NV01_NULL_OBJECT) {
nvRmApiFree(device->hRmClient,
device->hRmDevice,
ss->hSemaphoreMem);
}
nvRmApiFree(device->hRmClient,
device->hRmDevice,
ss->hSemaphoreSurface);
}
nvKmsKapiFree(ss);
return NULL;
}
void nvKmsKapiFreeSemaphoreSurface
(
struct NvKmsKapiDevice *device,
struct NvKmsKapiSemaphoreSurface *ss
)
{
if (device == NULL || ss == NULL) {
return;
}
if ((ss->hMaxSubmittedMem != NV01_NULL_OBJECT) &&
(ss->hMaxSubmittedMem != ss->hSemaphoreMem)) {
nvRmApiFree(device->hRmClient,
device->hRmDevice,
ss->hMaxSubmittedMem);
}
nvRmApiFree(device->hRmClient,
device->hRmDevice,
ss->hSemaphoreMem);
nvRmApiFree(device->hRmClient,
device->hRmSubDevice,
ss->hSemaphoreSurface);
nvKmsKapiFree(ss);
}
struct NvKmsKapiSemaphoreSurfaceCallback {
NvKmsSemaphoreSurfaceCallbackProc *pCallback;
void *pData;
NVOS10_EVENT_KERNEL_CALLBACK_EX rmCallback;
};
static void SemaphoreSurfaceKapiCallback(void *arg1, void *arg2, NvHandle hEvent,
NvU32 data, NvU32 status)
{
struct NvKmsKapiSemaphoreSurfaceCallback *cb = arg1;
cb->pCallback(cb->pData);
nvKmsKapiFree(cb);
}
NvKmsKapiRegisterWaiterResult
nvKmsKapiRegisterSemaphoreSurfaceCallback(
struct NvKmsKapiDevice *device,
struct NvKmsKapiSemaphoreSurface *semaphoreSurface,
NvKmsSemaphoreSurfaceCallbackProc *pCallback,
void *pData,
NvU64 index,
NvU64 wait_value,
NvU64 new_value,
struct NvKmsKapiSemaphoreSurfaceCallback **pCallbackHandle)
{
NvU32 ret;
struct NvKmsKapiSemaphoreSurfaceCallback *cb = NULL;
NV_SEMAPHORE_SURFACE_CTRL_REGISTER_WAITER_PARAMS waiterParams = { };
if (device == NULL) {
nvKmsKapiLogDebug(
"Invalid device while registering semaphore surface callback");
goto fail;
}
if ((semaphoreSurface == NULL) ||
((pCallback == NULL) && (new_value == 0))) {
nvKmsKapiLogDeviceDebug(
device,
"Invalid parameter while registering semaphore surface callback");
goto fail;
}
waiterParams.index = index;
waiterParams.waitValue = wait_value;
waiterParams.newValue = new_value;
if (pCallback) {
cb = nvKmsKapiCalloc(1, sizeof(*cb));
if (cb == NULL) {
nvKmsKapiLogDeviceDebug(
device,
"Failed to allocate memory for semaphore surface (0x%08x, 0x%08x) callback on index %" NvU64_fmtu " for value %" NvU64_fmtx,
device->hRmClient, semaphoreSurface->hSemaphoreSurface,
index, wait_value);
goto fail;
}
cb->pCallback = pCallback;
cb->pData = pData;
cb->rmCallback.func = SemaphoreSurfaceKapiCallback;
cb->rmCallback.arg = cb;
waiterParams.notificationHandle = (NvUPtr)&cb->rmCallback;
}
ret = nvRmApiControl(device->hRmClient,
semaphoreSurface->hSemaphoreSurface,
NV_SEMAPHORE_SURFACE_CTRL_CMD_REGISTER_WAITER,
&waiterParams,
sizeof(waiterParams));
switch (ret) {
case NVOS_STATUS_SUCCESS:
if (pCallback) {
*pCallbackHandle = cb;
}
return NVKMS_KAPI_REG_WAITER_SUCCESS;
case NVOS_STATUS_ERROR_ALREADY_SIGNALLED:
return NVKMS_KAPI_REG_WAITER_ALREADY_SIGNALLED;
default:
break;
}
fail:
nvKmsKapiFree(cb);
return NVKMS_KAPI_REG_WAITER_FAILED;
}
NvBool
nvKmsKapiUnregisterSemaphoreSurfaceCallback(
struct NvKmsKapiDevice *device,
struct NvKmsKapiSemaphoreSurface *semaphoreSurface,
NvU64 index,
NvU64 wait_value,
struct NvKmsKapiSemaphoreSurfaceCallback *callbackHandle)
{
NV_SEMAPHORE_SURFACE_CTRL_UNREGISTER_WAITER_PARAMS waiterParams = { };
NvU32 ret;
if (device == NULL) {
nvKmsKapiLogDebug(
"Invalid device while unregistering semaphore surface callback");
return NV_FALSE;
}
if ((semaphoreSurface == NULL) || (callbackHandle == NULL) ||
(wait_value == 0)) {
nvKmsKapiLogDeviceDebug(
device,
"Invalid parameter while unregistering semaphore surface callback");
return NV_FALSE;
}
/*
* Note this function does not actually dereference callbackHandle before
* making the RM control call. This is important, as there may exist a race
* such that the client is calling this function while another thread is
* running the callback and freeing its handle.
*
* The existance of this race seems to imply there is an additional hazard
* where a new callback may be registered against the same wait value during
* the first race, which this call would then mistakenly delete. That is
* impossible because the RM semaphore surface code would detect that such a
* waiter is already signaled and return without adding it to the waiter
* list.
*/
waiterParams.index = index;
waiterParams.waitValue = wait_value;
/*
* Manually perform the equivalent of &callbackHandle->rmCallback, but with
* semantics that make it clearer there is no access of the memory pointed
* to by callbackHandle.
*/
waiterParams.notificationHandle = (NvUPtr)callbackHandle +
offsetof(struct NvKmsKapiSemaphoreSurfaceCallback, rmCallback);
ret = nvRmApiControl(device->hRmClient,
semaphoreSurface->hSemaphoreSurface,
NV_SEMAPHORE_SURFACE_CTRL_CMD_UNREGISTER_WAITER,
&waiterParams,
sizeof(waiterParams));
switch (ret) {
case NVOS_STATUS_SUCCESS:
/*
* The callback was successfully unregistered, and will never run. Free
* its associated data.
*/
nvKmsKapiFree(callbackHandle);
return NV_TRUE;
default:
/*
* This code must assume failure to unregister for any reason indicates
* the callback is being run right now, or is on a list of pending
* callbacks which will be run in finite time. Do not free its data.
*/
return NV_FALSE;
}
}
NvBool
nvKmsKapiSetSemaphoreSurfaceValue(
struct NvKmsKapiDevice *device,
struct NvKmsKapiSemaphoreSurface *semaphoreSurface,
NvU64 index,
NvU64 new_value)
{
NvU32 ret;
NV_SEMAPHORE_SURFACE_CTRL_SET_VALUE_PARAMS setParams = { };
if (device == NULL) {
nvKmsKapiLogDebug(
"Invalid device used to set semaphore surface value");
return NV_FALSE;
}
if (semaphoreSurface == NULL) {
nvKmsKapiLogDeviceDebug(
device,
"Attempt to set value on Invalid semaphore surface");
return NV_FALSE;
}
setParams.index = index;
setParams.newValue = new_value;
ret = nvRmApiControl(device->hRmClient,
semaphoreSurface->hSemaphoreSurface,
NV_SEMAPHORE_SURFACE_CTRL_CMD_SET_VALUE,
&setParams,
sizeof(setParams));
if (ret != NVOS_STATUS_SUCCESS) {
return NV_FALSE;
}
return NV_TRUE;
}

View File

@@ -46,6 +46,7 @@
#include <ctrl/ctrl0000/ctrl0000client.h> /* NV0000_CTRL_CMD_CLIENT_GET_ADDR_SPACE_TYPE_VIDMEM */
#include <ctrl/ctrl0080/ctrl0080gpu.h> /* NV0080_CTRL_CMD_GPU_GET_NUM_SUBDEVICES */
#include <ctrl/ctrl0080/ctrl0080fb.h> /* NV0080_CTRL_CMD_FB_GET_CAPS_V2 */
#include <ctrl/ctrl2080/ctrl2080fb.h> /* NV2080_CTRL_CMD_FB_GET_SEMAPHORE_SURFACE_LAYOUT */
#include <ctrl/ctrl2080/ctrl2080unix.h> /* NV2080_CTRL_CMD_OS_UNIX_GC6_BLOCKER_REFCNT */
#include "ctrl/ctrl003e.h" /* NV003E_CTRL_CMD_GET_SURFACE_PHYS_PAGES */
@@ -914,6 +915,51 @@ static NvBool RevokePermissions
sizeof(paramsRevoke));
}
static NvBool GrantSubOwnership
(
NvS32 fd,
struct NvKmsKapiDevice *device
)
{
struct NvKmsGrantPermissionsParams paramsGrant = { };
struct NvKmsPermissions *perm = &paramsGrant.request.permissions;
if (device->hKmsDevice == 0x0) {
return NV_TRUE;
}
perm->type = NV_KMS_PERMISSIONS_TYPE_SUB_OWNER;
paramsGrant.request.fd = fd;
paramsGrant.request.deviceHandle = device->hKmsDevice;
return nvkms_ioctl_from_kapi(device->pKmsOpen,
NVKMS_IOCTL_GRANT_PERMISSIONS, &paramsGrant,
sizeof(paramsGrant));
}
static NvBool RevokeSubOwnership
(
struct NvKmsKapiDevice *device
)
{
struct NvKmsRevokePermissionsParams paramsRevoke = { };
if (device->hKmsDevice == 0x0) {
return NV_TRUE;
}
paramsRevoke.request.permissionsTypeBitmask =
NVBIT(NV_KMS_PERMISSIONS_TYPE_FLIPPING) |
NVBIT(NV_KMS_PERMISSIONS_TYPE_MODESET) |
NVBIT(NV_KMS_PERMISSIONS_TYPE_SUB_OWNER);
paramsRevoke.request.deviceHandle = device->hKmsDevice;
return nvkms_ioctl_from_kapi(device->pKmsOpen,
NVKMS_IOCTL_REVOKE_PERMISSIONS, &paramsRevoke,
sizeof(paramsRevoke));
}
static NvBool DeclareEventInterest
(
const struct NvKmsKapiDevice *device,
@@ -941,12 +987,30 @@ static NvBool GetDeviceResourcesInfo
)
{
struct NvKmsQueryDispParams paramsDisp = { };
NV2080_CTRL_FB_GET_SEMAPHORE_SURFACE_LAYOUT_PARAMS semsurfLayoutParams = { };
NvBool status = NV_FALSE;
NvU32 ret;
NvU32 i;
nvkms_memset(info, 0, sizeof(*info));
ret = nvRmApiControl(device->hRmClient,
device->hRmSubDevice,
NV2080_CTRL_CMD_FB_GET_SEMAPHORE_SURFACE_LAYOUT,
&semsurfLayoutParams,
sizeof(semsurfLayoutParams));
if (ret == NVOS_STATUS_SUCCESS) {
info->caps.semsurf.stride = semsurfLayoutParams.size;
info->caps.semsurf.maxSubmittedOffset =
semsurfLayoutParams.maxSubmittedSemaphoreValueOffset;
} else {
/* Non-fatal. No semaphore surface support. */
info->caps.semsurf.stride = 0;
info->caps.semsurf.maxSubmittedOffset = 0;
}
info->caps.hasVideoMemory = !device->isSOC;
info->caps.genericPageKind = device->caps.genericPageKind;
@@ -2436,16 +2500,18 @@ static NvBool AssignSyncObjectConfig(
static void AssignHDRMetadataConfig(
const struct NvKmsKapiLayerConfig *layerConfig,
const struct NvKmsKapiLayerRequestedConfig *layerRequestedConfig,
const NvU32 layer,
struct NvKmsFlipCommonParams *params)
struct NvKmsFlipCommonParams *params,
NvBool bFromKmsSetMode)
{
if (layerConfig->hdrMetadataSpecified) {
params->layer[layer].hdr.enabled = TRUE;
params->layer[layer].hdr.specified = TRUE;
params->layer[layer].hdr.staticMetadata = layerConfig->hdrMetadata;
} else {
params->layer[layer].hdr.enabled = FALSE;
params->layer[layer].hdr.specified = TRUE;
params->layer[layer].hdr.specified =
bFromKmsSetMode || layerRequestedConfig->flags.hdrMetadataChanged;
params->layer[layer].hdr.enabled =
layerConfig->hdrMetadata.enabled;
if (layerConfig->hdrMetadata.enabled) {
params->layer[layer].hdr.staticMetadata =
layerConfig->hdrMetadata.val;
}
}
@@ -2513,15 +2579,30 @@ static NvBool NvKmsKapiOverlayLayerConfigToKms(
params->layer[layer].compositionParams.specified = TRUE;
params->layer[layer].minPresentInterval =
layerConfig->minPresentInterval;
params->layer[layer].colorSpace.val = layerConfig->inputColorSpace;
params->layer[layer].colorSpace.specified = TRUE;
}
params->layer[layer].sizeIn.val.width = layerConfig->srcWidth;
params->layer[layer].sizeIn.val.height = layerConfig->srcHeight;
params->layer[layer].sizeIn.specified = TRUE;
if (layerRequestedConfig->flags.cscChanged) {
params->layer[layer].csc.specified = NV_TRUE;
params->layer[layer].csc.useMain = layerConfig->cscUseMain;
if (!layerConfig->cscUseMain) {
params->layer[layer].csc.matrix = layerConfig->csc;
}
}
params->layer[layer].sizeOut.val.width = layerConfig->dstWidth;
params->layer[layer].sizeOut.val.height = layerConfig->dstHeight;
params->layer[layer].sizeOut.specified = TRUE;
if (layerRequestedConfig->flags.srcWHChanged || bFromKmsSetMode) {
params->layer[layer].sizeIn.val.width = layerConfig->srcWidth;
params->layer[layer].sizeIn.val.height = layerConfig->srcHeight;
params->layer[layer].sizeIn.specified = TRUE;
}
if (layerRequestedConfig->flags.dstWHChanged || bFromKmsSetMode) {
params->layer[layer].sizeOut.val.width = layerConfig->dstWidth;
params->layer[layer].sizeOut.val.height = layerConfig->dstHeight;
params->layer[layer].sizeOut.specified = TRUE;
}
if (layerRequestedConfig->flags.dstXYChanged || bFromKmsSetMode) {
params->layer[layer].outputPosition.val.x = layerConfig->dstX;
@@ -2530,10 +2611,8 @@ static NvBool NvKmsKapiOverlayLayerConfigToKms(
params->layer[layer].outputPosition.specified = NV_TRUE;
}
params->layer[layer].colorspace.val = layerConfig->inputColorSpace;
params->layer[layer].colorspace.specified = TRUE;
AssignHDRMetadataConfig(layerConfig, layer, params);
AssignHDRMetadataConfig(layerConfig, layerRequestedConfig, layer,
params, bFromKmsSetMode);
if (commit) {
NvU32 nextIndex = NVKMS_KAPI_INC_NOTIFIER_INDEX(
@@ -2619,6 +2698,9 @@ static NvBool NvKmsKapiPrimaryLayerConfigToKms(
}
}
params->layer[NVKMS_MAIN_LAYER].colorSpace.val = layerConfig->inputColorSpace;
params->layer[NVKMS_MAIN_LAYER].colorSpace.specified = TRUE;
changed = TRUE;
}
@@ -2630,10 +2712,18 @@ static NvBool NvKmsKapiPrimaryLayerConfigToKms(
changed = TRUE;
}
params->layer[NVKMS_MAIN_LAYER].colorspace.val = layerConfig->inputColorSpace;
params->layer[NVKMS_MAIN_LAYER].colorspace.specified = TRUE;
if (layerRequestedConfig->flags.cscChanged) {
nvAssert(!layerConfig->cscUseMain);
AssignHDRMetadataConfig(layerConfig, NVKMS_MAIN_LAYER, params);
params->layer[NVKMS_MAIN_LAYER].csc.specified = NV_TRUE;
params->layer[NVKMS_MAIN_LAYER].csc.useMain = FALSE;
params->layer[NVKMS_MAIN_LAYER].csc.matrix = layerConfig->csc;
changed = TRUE;
}
AssignHDRMetadataConfig(layerConfig, layerRequestedConfig, NVKMS_MAIN_LAYER,
params, bFromKmsSetMode);
if (commit && changed) {
NvU32 nextIndex = NVKMS_KAPI_INC_NOTIFIER_INDEX(
@@ -2707,6 +2797,47 @@ static NvBool NvKmsKapiLayerConfigToKms(
bFromKmsSetMode);
}
static void NvKmsKapiHeadLutConfigToKms(
const struct NvKmsKapiHeadModeSetConfig *modeSetConfig,
struct NvKmsSetLutCommonParams *lutParams)
{
struct NvKmsSetInputLutParams *input = &lutParams->input;
struct NvKmsSetOutputLutParams *output = &lutParams->output;
/* input LUT */
input->specified = modeSetConfig->lut.input.specified;
input->depth = modeSetConfig->lut.input.depth;
input->start = modeSetConfig->lut.input.start;
input->end = modeSetConfig->lut.input.end;
input->pRamps = nvKmsPointerToNvU64(modeSetConfig->lut.input.pRamps);
/* output LUT */
output->specified = modeSetConfig->lut.output.specified;
output->enabled = modeSetConfig->lut.output.enabled;
output->pRamps = nvKmsPointerToNvU64(modeSetConfig->lut.output.pRamps);
}
static NvBool AnyLayerTransferFunctionChanged(
const struct NvKmsKapiHeadRequestedConfig *headRequestedConfig)
{
NvU32 layer;
for (layer = 0;
layer < ARRAY_LEN(headRequestedConfig->layerRequestedConfig);
layer++) {
const struct NvKmsKapiLayerRequestedConfig *layerRequestedConfig =
&headRequestedConfig->layerRequestedConfig[layer];
if (layerRequestedConfig->flags.tfChanged) {
return NV_TRUE;
}
}
return NV_FALSE;
}
static NvBool GetOutputTransferFunction(
const struct NvKmsKapiHeadRequestedConfig *headRequestedConfig,
enum NvKmsOutputTf *tf)
@@ -2724,7 +2855,7 @@ static NvBool GetOutputTransferFunction(
const struct NvKmsKapiLayerConfig *layerConfig =
&layerRequestedConfig->config;
if (layerConfig->hdrMetadataSpecified) {
if (layerConfig->hdrMetadata.enabled) {
if (!found) {
*tf = layerConfig->tf;
found = NV_TRUE;
@@ -2797,6 +2928,10 @@ static NvBool NvKmsKapiRequestedModeSetConfigToKms(
NvKmsKapiDisplayModeToKapi(&headModeSetConfig->mode, &paramsHead->mode);
if (headRequestedConfig->flags.lutChanged) {
NvKmsKapiHeadLutConfigToKms(headModeSetConfig, &paramsHead->flip.lut);
}
NvKmsKapiCursorConfigToKms(&headRequestedConfig->cursorRequestedConfig,
&paramsHead->flip,
NV_TRUE /* bFromKmsSetMode */);
@@ -2825,6 +2960,19 @@ static NvBool NvKmsKapiRequestedModeSetConfigToKms(
paramsHead->flip.tf.val = tf;
paramsHead->flip.tf.specified = NV_TRUE;
paramsHead->flip.hdrInfoFrame.specified = NV_TRUE;
paramsHead->flip.hdrInfoFrame.enabled =
headModeSetConfig->hdrInfoFrame.enabled;
if (headModeSetConfig->hdrInfoFrame.enabled) {
paramsHead->flip.hdrInfoFrame.eotf =
headModeSetConfig->hdrInfoFrame.eotf;
paramsHead->flip.hdrInfoFrame.staticMetadata =
headModeSetConfig->hdrInfoFrame.staticMetadata;
}
paramsHead->flip.colorimetry.specified = NV_TRUE;
paramsHead->flip.colorimetry.val = headModeSetConfig->colorimetry;
paramsHead->viewPortSizeIn.width =
headModeSetConfig->mode.timings.hVisible;
paramsHead->viewPortSizeIn.height =
@@ -2846,6 +2994,7 @@ static NvBool NvKmsKapiRequestedModeSetConfigToKms(
static NvBool KmsSetMode(
struct NvKmsKapiDevice *device,
const struct NvKmsKapiRequestedModeSetConfig *requestedConfig,
struct NvKmsKapiModeSetReplyConfig *replyConfig,
const NvBool commit)
{
struct NvKmsSetModeParams *params = NULL;
@@ -2868,6 +3017,11 @@ static NvBool KmsSetMode(
NVKMS_IOCTL_SET_MODE,
params, sizeof(*params));
replyConfig->flipResult =
(params->reply.status == NVKMS_SET_MODE_STATUS_SUCCESS) ?
NV_KMS_FLIP_RESULT_SUCCESS :
NV_KMS_FLIP_RESULT_INVALID_PARAMS;
if (!status) {
nvKmsKapiLogDeviceDebug(
device,
@@ -2966,7 +3120,6 @@ static NvBool KmsFlip(
&requestedConfig->headRequestedConfig[head];
const struct NvKmsKapiHeadModeSetConfig *headModeSetConfig =
&headRequestedConfig->modeSetConfig;
enum NvKmsOutputTf tf;
struct NvKmsFlipCommonParams *flipParams = NULL;
@@ -3006,17 +3159,42 @@ static NvBool KmsFlip(
}
}
status = GetOutputTransferFunction(headRequestedConfig, &tf);
if (status != NV_TRUE) {
goto done;
flipParams->tf.specified =
AnyLayerTransferFunctionChanged(headRequestedConfig);
if (flipParams->tf.specified) {
enum NvKmsOutputTf tf;
status = GetOutputTransferFunction(headRequestedConfig, &tf);
if (status != NV_TRUE) {
goto done;
}
flipParams->tf.val = tf;
}
flipParams->tf.val = tf;
flipParams->tf.specified = NV_TRUE;
flipParams->hdrInfoFrame.specified =
headRequestedConfig->flags.hdrInfoFrameChanged;
if (flipParams->hdrInfoFrame.specified) {
flipParams->hdrInfoFrame.enabled =
headModeSetConfig->hdrInfoFrame.enabled;
if (headModeSetConfig->hdrInfoFrame.enabled) {
flipParams->hdrInfoFrame.eotf =
headModeSetConfig->hdrInfoFrame.eotf;
flipParams->hdrInfoFrame.staticMetadata =
headModeSetConfig->hdrInfoFrame.staticMetadata;
}
}
flipParams->colorimetry.specified =
headRequestedConfig->flags.colorimetryChanged;
if (flipParams->colorimetry.specified) {
flipParams->colorimetry.val = headModeSetConfig->colorimetry;
}
if (headModeSetConfig->vrrEnabled) {
params->request.allowVrr = NV_TRUE;
}
if (headRequestedConfig->flags.lutChanged) {
NvKmsKapiHeadLutConfigToKms(headModeSetConfig, &flipParams->lut);
}
}
if (params->request.numFlipHeads == 0) {
@@ -3027,6 +3205,8 @@ static NvBool KmsFlip(
NVKMS_IOCTL_FLIP,
params, sizeof(*params));
replyConfig->flipResult = params->reply.flipResult;
if (!status) {
nvKmsKapiLogDeviceDebug(
device,
@@ -3129,12 +3309,16 @@ static NvBool ApplyModeSetConfig(
}
if (bRequiredModeset) {
return KmsSetMode(device, requestedConfig, commit);
return KmsSetMode(device, requestedConfig, replyConfig, commit);
}
return KmsFlip(device, requestedConfig, replyConfig, commit);
}
/*
* This executes without the nvkms_lock held. The lock will be grabbed
* during the kapi dispatching contained in this function.
*/
void nvKmsKapiHandleEventQueueChange
(
struct NvKmsKapiDevice *device
@@ -3279,6 +3463,8 @@ NvBool nvKmsKapiGetFunctionsTableInternal
funcsTable->grantPermissions = GrantPermissions;
funcsTable->revokePermissions = RevokePermissions;
funcsTable->grantSubOwnership = GrantSubOwnership;
funcsTable->revokeSubOwnership = RevokeSubOwnership;
funcsTable->declareEventInterest = DeclareEventInterest;
@@ -3320,5 +3506,14 @@ NvBool nvKmsKapiGetFunctionsTableInternal
funcsTable->isMemoryValidForDisplay = IsMemoryValidForDisplay;
funcsTable->importSemaphoreSurface = nvKmsKapiImportSemaphoreSurface;
funcsTable->freeSemaphoreSurface = nvKmsKapiFreeSemaphoreSurface;
funcsTable->registerSemaphoreSurfaceCallback =
nvKmsKapiRegisterSemaphoreSurfaceCallback;
funcsTable->unregisterSemaphoreSurfaceCallback =
nvKmsKapiUnregisterSemaphoreSurfaceCallback;
funcsTable->setSemaphoreSurfaceValue =
nvKmsKapiSetSemaphoreSurfaceValue;
return NV_TRUE;
}