--- src/nvidia-modeset/nvidia-modeset-freebsd.c.orig 2023-03-28 22:14:28 UTC +++ src/nvidia-modeset/nvidia-modeset-freebsd.c @@ -368,6 +368,7 @@ struct nvkms_timer_t { NvBool cancel; NvBool complete; NvBool isRefPtr; + NvBool needsNvkmsLock; NvBool callout_created; nvkms_timer_proc_t *proc; void *dataPtr; @@ -406,7 +407,14 @@ static void nvkms_taskqueue_callback(void *arg, int pe callout_drain(&timer->callout); } - sx_xlock(&nvkms_lock); + /* + * Only lock if this timer requests it. DRM's callback nv_drm_event_callback + * will not need this, since it may reenter nvkms through the kapi and lock + * nvkms_lock then. + */ + if (timer->needsNvkmsLock) { + sx_xlock(&nvkms_lock); + } if (timer->isRefPtr) { // If the object this timer refers to was destroyed, treat the timer as @@ -424,11 +432,13 @@ static void nvkms_taskqueue_callback(void *arg, int pe timer->complete = NV_TRUE; } + if (timer->needsNvkmsLock) { + sx_xunlock(&nvkms_lock); + } + if (timer->cancel || timer->isRefPtr) { nvkms_free(timer, sizeof(*timer)); } - - sx_xunlock(&nvkms_lock); } static void nvkms_callout_callback(void *arg) @@ -441,11 +451,13 @@ nvkms_init_timer(struct nvkms_timer_t *timer, nvkms_ti static void nvkms_init_timer(struct nvkms_timer_t *timer, nvkms_timer_proc_t *proc, - void *dataPtr, NvU32 dataU32, NvBool isRefPtr, NvU64 usec) + void *dataPtr, NvU32 dataU32, NvBool isRefPtr, NvU64 usec, + NvBool needsNvkmsLock) { timer->cancel = NV_FALSE; timer->complete = NV_FALSE; timer->isRefPtr = isRefPtr; + timer->needsNvkmsLock = needsNvkmsLock; timer->proc = proc; timer->dataPtr = dataPtr; @@ -479,19 +491,27 @@ nvkms_init_timer(struct nvkms_timer_t *timer, nvkms_ti mtx_unlock_spin(&nvkms_timers.lock); } -nvkms_timer_handle_t* -nvkms_alloc_timer(nvkms_timer_proc_t *proc, - void *dataPtr, NvU32 dataU32, - NvU64 usec) +static nvkms_timer_handle_t* +nvkms_alloc_timer_locked(nvkms_timer_proc_t *proc, + void *dataPtr, NvU32 dataU32, + NvU64 usec, NvBool needsNvkmsLock) { // nvkms_alloc_timer cannot be called from an interrupt context. struct nvkms_timer_t *timer = nvkms_alloc(sizeof(*timer), NV_TRUE); if (timer) { - nvkms_init_timer(timer, proc, dataPtr, dataU32, NV_FALSE, usec); + nvkms_init_timer(timer, proc, dataPtr, dataU32, NV_FALSE, usec, needsNvkmsLock); } return timer; } +nvkms_timer_handle_t* +nvkms_alloc_timer(nvkms_timer_proc_t *proc, + void *dataPtr, NvU32 dataU32, + NvU64 usec) +{ + return nvkms_alloc_timer_locked(proc, dataPtr, dataU32, usec, NV_TRUE); +} + NvBool nvkms_alloc_timer_with_ref_ptr(nvkms_timer_proc_t *proc, struct nvkms_ref_ptr *ref_ptr, @@ -506,7 +526,7 @@ nvkms_alloc_timer_with_ref_ptr(nvkms_timer_proc_t *pro // Reference the ref_ptr to make sure that it doesn't get freed before // the timer fires. nvkms_inc_ref(ref_ptr); - nvkms_init_timer(timer, proc, ref_ptr, dataU32, NV_TRUE, usec); + nvkms_init_timer(timer, proc, ref_ptr, dataU32, NV_TRUE, usec, NV_TRUE); } return timer != NULL; @@ -570,10 +590,11 @@ nvkms_event_queue_changed(nvkms_per_open_handle_t *pOp break; case NVKMS_CLIENT_KERNEL_SPACE: if (!popen->kernel.task) { - popen->kernel.task = nvkms_alloc_timer(nvkms_kapi_task_callback, - popen, - 0, /* dataU32 */ - 0 /* callout delay */); + popen->kernel.task = nvkms_alloc_timer_locked(nvkms_kapi_task_callback, + popen, + 0, /* dataU32 */ + 0, /* callout delay */ + NV_FALSE); } break; } @@ -828,10 +849,11 @@ static struct nvkms_per_open *nvkms_open_common(enum N case NVKMS_CLIENT_KERNEL_SPACE: /* enqueue our new task */ popen->kernel.device = device; - popen->kernel.task = nvkms_alloc_timer(nvkms_kapi_task_callback, - popen, - 0, /* dataU32 */ - 0 /* callout delay */); + popen->kernel.task = nvkms_alloc_timer_locked(nvkms_kapi_task_callback, + popen, + 0, /* dataU32 */ + 0, /* callout delay */ + NV_FALSE); break; }