diff --git a/kernel-open/nvidia/nv.c b/kernel-open/nvidia/nv.c index 99792de96..ccef3f294 100644 --- a/kernel-open/nvidia/nv.c +++ b/kernel-open/nvidia/nv.c @@ -4042,6 +4042,16 @@ int NV_API_CALL nv_get_event( nvidia_event_t *nvet; unsigned long eflags; + // + // Note that the head read/write is not atomic when done outside of the + // spinlock, so this might not be a valid pointer at all. But if we read + // NULL here that means that the value indeed was NULL and we can bail + // early since there's no events. Otherwise, we have to do a proper read + // under a spinlock. + // + if (nvlfp->event_data_head == NULL) + return NV_ERR_GENERIC; + NV_SPIN_LOCK_IRQSAVE(&nvlfp->fp_lock, eflags); nvet = nvlfp->event_data_head; diff --git a/src/nvidia/arch/nvalloc/unix/include/osapi.h b/src/nvidia/arch/nvalloc/unix/include/osapi.h index f91e3aa51..640155e97 100644 --- a/src/nvidia/arch/nvalloc/unix/include/osapi.h +++ b/src/nvidia/arch/nvalloc/unix/include/osapi.h @@ -121,9 +121,6 @@ NvBool RmGpuHasIOSpaceEnabled (nv_state_t *); void RmFreeUnusedClients (nv_state_t *, nv_file_private_t *); NV_STATUS RmIoctl (nv_state_t *, nv_file_private_t *, NvU32, void *, NvU32); -NV_STATUS RmAllocOsEvent (NvHandle, nv_file_private_t *, NvU32); -NV_STATUS RmFreeOsEvent (NvHandle, NvU32); - void RmI2cAddGpuPorts(nv_state_t *); NV_STATUS RmInitX86EmuState(OBJGPU *); @@ -141,9 +138,6 @@ int amd_msr_c0011022_incompatible(OBJOS *); NV_STATUS rm_get_adapter_status (nv_state_t *, NvU32 *); -NV_STATUS rm_alloc_os_event (NvHandle, nv_file_private_t *, NvU32); -NV_STATUS rm_free_os_event (NvHandle, NvU32); -NV_STATUS rm_get_event_data (nv_file_private_t *, NvP64, NvU32 *); void rm_client_free_os_events (NvHandle); NV_STATUS rm_create_mmap_context (NvHandle, NvHandle, NvHandle, NvP64, NvU64, NvU64, NvU32, NvU32); diff --git a/src/nvidia/arch/nvalloc/unix/src/escape.c b/src/nvidia/arch/nvalloc/unix/src/escape.c index de0995136..1046b19f9 100644 --- a/src/nvidia/arch/nvalloc/unix/src/escape.c +++ b/src/nvidia/arch/nvalloc/unix/src/escape.c @@ -677,52 +677,6 @@ NV_STATUS RmIoctl( break; } - case NV_ESC_ALLOC_OS_EVENT: - { - nv_ioctl_alloc_os_event_t *pApi = data; - - if (dataSize != sizeof(nv_ioctl_alloc_os_event_t)) - { - rmStatus = NV_ERR_INVALID_ARGUMENT; - goto done; - } - - pApi->Status = rm_alloc_os_event(pApi->hClient, - nvfp, - pApi->fd); - break; - } - - case NV_ESC_FREE_OS_EVENT: - { - nv_ioctl_free_os_event_t *pApi = data; - - if (dataSize != sizeof(nv_ioctl_free_os_event_t)) - { - rmStatus = NV_ERR_INVALID_ARGUMENT; - goto done; - } - - pApi->Status = rm_free_os_event(pApi->hClient, pApi->fd); - break; - } - - case NV_ESC_RM_GET_EVENT_DATA: - { - NVOS41_PARAMETERS *pApi = data; - - if (dataSize != sizeof(NVOS41_PARAMETERS)) - { - rmStatus = NV_ERR_INVALID_ARGUMENT; - goto done; - } - - pApi->status = rm_get_event_data(nvfp, - pApi->pEvent, - &pApi->MoreEvents); - break; - } - case NV_ESC_STATUS_CODE: { nv_state_t *pNv; diff --git a/src/nvidia/arch/nvalloc/unix/src/osapi.c b/src/nvidia/arch/nvalloc/unix/src/osapi.c index fd3124661..512497500 100644 --- a/src/nvidia/arch/nvalloc/unix/src/osapi.c +++ b/src/nvidia/arch/nvalloc/unix/src/osapi.c @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -406,6 +407,39 @@ static void free_os_events( portSyncSpinlockRelease(nv->event_spinlock); } +static NV_STATUS get_os_event_data( + nv_file_private_t *nvfp, + NvP64 pEvent, + NvU32 *MoreEvents +) +{ + nv_event_t nv_event; + NvUnixEvent *nv_unix_event; + NV_STATUS status; + + status = os_alloc_mem((void**)&nv_unix_event, sizeof(NvUnixEvent)); + if (status != NV_OK) + return status; + + status = nv_get_event(nvfp, &nv_event, MoreEvents); + if (status != NV_OK) + { + status = NV_ERR_OPERATING_SYSTEM; + goto done; + } + + os_mem_set(nv_unix_event, 0, sizeof(NvUnixEvent)); + nv_unix_event->hObject = nv_event.hObject; + nv_unix_event->NotifyIndex = nv_event.index; + nv_unix_event->info32 = nv_event.info32; + nv_unix_event->info16 = nv_event.info16; + + status = os_memcpy_to_user(NvP64_VALUE(pEvent), nv_unix_event, sizeof(NvUnixEvent)); +done: + os_free_mem(nv_unix_event); + return status; +} + void rm_client_free_os_events( NvHandle client ) @@ -482,6 +516,12 @@ static NV_STATUS allocate_os_event( goto done; } + new_event->hParent = hParent; + new_event->nvfp = nvfp; + new_event->fd = fd; + new_event->active = NV_TRUE; + new_event->refcount = 0; + portSyncSpinlockAcquire(nv->event_spinlock); for (event = nv->event_list; event; event = event->next) { @@ -496,45 +536,26 @@ static NV_STATUS allocate_os_event( new_event->next = nv->event_list; nv->event_list = new_event; + nvfp->bCleanupRmapi = NV_TRUE; portSyncSpinlockRelease(nv->event_spinlock); done: if (status == NV_OK) { - new_event->hParent = hParent; - new_event->nvfp = nvfp; - new_event->fd = fd; - new_event->active = NV_TRUE; - new_event->refcount = 0; - - nvfp->bCleanupRmapi = NV_TRUE; - NV_PRINTF(LEVEL_INFO, "allocated OS event:\n"); NV_PRINTF(LEVEL_INFO, " hParent: 0x%x\n", hParent); NV_PRINTF(LEVEL_INFO, " fd: %d\n", fd); } else { + NV_PRINTF(LEVEL_ERROR, "failed to allocate OS event: 0x%08x\n", status); + status = NV_ERR_INSUFFICIENT_RESOURCES; portMemFree(new_event); } return status; } -NV_STATUS RmAllocOsEvent( - NvHandle hParent, - nv_file_private_t *nvfp, - NvU32 fd -) -{ - if (NV_OK != allocate_os_event(hParent, nvfp, fd)) - { - NV_PRINTF(LEVEL_ERROR, "failed to allocate OS event\n"); - return NV_ERR_INSUFFICIENT_RESOURCES; - } - return NV_OK; -} - static NV_STATUS free_os_event( NvHandle hParent, NvU32 fd @@ -585,18 +606,6 @@ static NV_STATUS free_os_event( return result; } -NV_STATUS RmFreeOsEvent( - NvHandle hParent, - NvU32 fd -) -{ - if (NV_OK != free_os_event(hParent, fd)) - { - return NV_ERR_INVALID_EVENT; - } - return NV_OK; -} - static void RmExecuteWorkItem( void *pWorkItem ) @@ -656,40 +665,6 @@ done: portMemFree((void *)pWi); } -static NV_STATUS RmGetEventData( - nv_file_private_t *nvfp, - NvP64 pEvent, - NvU32 *MoreEvents, - NvBool bUserModeArgs -) -{ - NV_STATUS RmStatus; - NvUnixEvent *pKernelEvent = NULL; - nv_event_t nv_event; - RMAPI_PARAM_COPY paramCopy; - - RmStatus = nv_get_event(nvfp, &nv_event, MoreEvents); - if (RmStatus != NV_OK) - return NV_ERR_OPERATING_SYSTEM; - - // setup for access to client's parameters - RMAPI_PARAM_COPY_INIT(paramCopy, pKernelEvent, pEvent, 1, sizeof(NvUnixEvent)); - RmStatus = rmapiParamsAcquire(¶mCopy, bUserModeArgs); - if (RmStatus != NV_OK) - return NV_ERR_OPERATING_SYSTEM; - - pKernelEvent->hObject = nv_event.hObject; - pKernelEvent->NotifyIndex = nv_event.index; - pKernelEvent->info32 = nv_event.info32; - pKernelEvent->info16 = nv_event.info16; - - // release client buffer access, with copyout as needed - if (rmapiParamsRelease(¶mCopy) != NV_OK) - return NV_ERR_OPERATING_SYSTEM; - - return NV_OK; -} - static NV_STATUS RmAccessRegistry( NvHandle hClient, NvHandle hObject, @@ -2738,16 +2713,68 @@ NV_STATUS NV_API_CALL rm_ioctl( NvU32 dataSize ) { - NV_STATUS rmStatus; + NV_STATUS rmStatus = NV_OK; THREAD_STATE_NODE threadState; void *fp; NV_ENTER_RM_RUNTIME(sp,fp); - threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE); - rmStatus = RmIoctl(pNv, nvfp, Command, pData, dataSize); + // + // Some ioctls are handled entirely inside the OS layer and don't need to + // suffer the overhead of calling into RM core. + // + switch (Command) + { + case NV_ESC_ALLOC_OS_EVENT: + { + nv_ioctl_alloc_os_event_t *pApi = pData; + + if (dataSize != sizeof(nv_ioctl_alloc_os_event_t)) + { + rmStatus = NV_ERR_INVALID_ARGUMENT; + break; + } + + pApi->Status = allocate_os_event(pApi->hClient, nvfp, pApi->fd); + break; + } + case NV_ESC_FREE_OS_EVENT: + { + nv_ioctl_free_os_event_t *pApi = pData; + + if (dataSize != sizeof(nv_ioctl_free_os_event_t)) + { + rmStatus = NV_ERR_INVALID_ARGUMENT; + break; + } + + pApi->Status = free_os_event(pApi->hClient, pApi->fd); + break; + } + case NV_ESC_RM_GET_EVENT_DATA: + { + NVOS41_PARAMETERS *pApi = pData; + + if (dataSize != sizeof(NVOS41_PARAMETERS)) + { + rmStatus = NV_ERR_INVALID_ARGUMENT; + break; + } + + pApi->status = get_os_event_data(nvfp, + pApi->pEvent, + &pApi->MoreEvents); + break; + } + default: + { + threadStateInit(&threadState, THREAD_STATE_FLAGS_NONE); + rmStatus = RmIoctl(pNv, nvfp, Command, pData, dataSize); + threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE); + break; + } + } - threadStateFree(&threadState, THREAD_STATE_FLAGS_NONE); NV_EXIT_RM_RUNTIME(sp,fp); return rmStatus; @@ -2882,65 +2909,6 @@ void NV_API_CALL rm_unbind_lock( NV_EXIT_RM_RUNTIME(sp,fp); } -NV_STATUS rm_alloc_os_event( - NvHandle hClient, - nv_file_private_t *nvfp, - NvU32 fd -) -{ - NV_STATUS RmStatus; - - // LOCK: acquire API lock - if ((RmStatus = rmapiLockAcquire(RMAPI_LOCK_FLAGS_READ, RM_LOCK_MODULES_EVENT)) == NV_OK) - { - RmStatus = RmAllocOsEvent(hClient, nvfp, fd); - - // UNLOCK: release API lock - rmapiLockRelease(); - } - - return RmStatus; -} - -NV_STATUS rm_free_os_event( - NvHandle hClient, - NvU32 fd -) -{ - NV_STATUS RmStatus; - - // LOCK: acquire API lock - if ((RmStatus = rmapiLockAcquire(RMAPI_LOCK_FLAGS_READ, RM_LOCK_MODULES_EVENT)) == NV_OK) - { - RmStatus = RmFreeOsEvent(hClient, fd); - - // UNLOCK: release API lock - rmapiLockRelease(); - } - - return RmStatus; -} - -NV_STATUS rm_get_event_data( - nv_file_private_t *nvfp, - NvP64 pEvent, - NvU32 *MoreEvents -) -{ - NV_STATUS RmStatus; - - // LOCK: acquire API lock - if ((RmStatus = rmapiLockAcquire(RMAPI_LOCK_FLAGS_READ, RM_LOCK_MODULES_EVENT)) == NV_OK) - { - RmStatus = RmGetEventData(nvfp, pEvent, MoreEvents, NV_TRUE); - - // UNLOCK: release API lock - rmapiLockRelease(); - } - - return RmStatus; -} - NV_STATUS NV_API_CALL rm_read_registry_dword( nvidia_stack_t *sp, nv_state_t *nv, diff --git a/src/nvidia/exports_link_command.txt b/src/nvidia/exports_link_command.txt index de3cf86df..b92185de9 100644 --- a/src/nvidia/exports_link_command.txt +++ b/src/nvidia/exports_link_command.txt @@ -1,6 +1,5 @@ --undefined=rm_disable_adapter --undefined=rm_execute_work_item ---undefined=rm_free_os_event --undefined=rm_free_private_state --undefined=rm_cleanup_file_private --undefined=rm_unbind_lock