// SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * * Copyright 2011-2023 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sub license, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * USE OR OTHER DEALINGS IN THE SOFTWARE. * **************************************************************************/ #include <linux/sched/signal.h> #include "vmwgfx_drv.h" #define VMW_FENCE_WRAP … struct vmw_fence_manager { … }; struct vmw_user_fence { … }; /** * struct vmw_event_fence_action - fence action that delivers a drm event. * * @action: A struct vmw_fence_action to hook up to a fence. * @event: A pointer to the pending event. * @fence: A referenced pointer to the fence to keep it alive while @action * hangs on it. * @dev: Pointer to a struct drm_device so we can access the event stuff. * @tv_sec: If non-null, the variable pointed to will be assigned * current time tv_sec val when the fence signals. * @tv_usec: Must be set if @tv_sec is set, and the variable pointed to will * be assigned the current time tv_usec val when the fence signals. */ struct vmw_event_fence_action { … }; static struct vmw_fence_manager * fman_from_fence(struct vmw_fence_obj *fence) { … } static u32 vmw_fence_goal_read(struct vmw_private *vmw) { … } static void vmw_fence_goal_write(struct vmw_private *vmw, u32 value) { … } /* * Note on fencing subsystem usage of irqs: * Typically the vmw_fences_update function is called * * a) When a new fence seqno has been submitted by the fifo code. * b) On-demand when we have waiters. Sleeping waiters will switch on the * ANY_FENCE irq and call vmw_fences_update function each time an ANY_FENCE * irq is received. When the last fence waiter is gone, that IRQ is masked * away. * * In situations where there are no waiters and we don't submit any new fences, * fence objects may not be signaled. This is perfectly OK, since there are * no consumers of the signaled data, but that is NOT ok when there are fence * actions attached to a fence. The fencing subsystem then makes use of the * FENCE_GOAL irq and sets the fence goal seqno to that of the next fence * which has an action attached, and each time vmw_fences_update is called, * the subsystem makes sure the fence goal seqno is updated. * * The fence goal seqno irq is on as long as there are unsignaled fence * objects with actions attached to them. */ static void vmw_fence_obj_destroy(struct dma_fence *f) { … } static const char *vmw_fence_get_driver_name(struct dma_fence *f) { … } static const char *vmw_fence_get_timeline_name(struct dma_fence *f) { … } static bool vmw_fence_enable_signaling(struct dma_fence *f) { … } struct vmwgfx_wait_cb { … }; static void vmwgfx_wait_cb(struct dma_fence *fence, struct dma_fence_cb *cb) { … } static void __vmw_fences_update(struct vmw_fence_manager *fman); static long vmw_fence_wait(struct dma_fence *f, bool intr, signed long timeout) { … } static const struct dma_fence_ops vmw_fence_ops = …; /* * Execute signal actions on fences recently signaled. * This is done from a workqueue so we don't have to execute * signal actions from atomic context. */ static void vmw_fence_work_func(struct work_struct *work) { … } struct vmw_fence_manager *vmw_fence_manager_init(struct vmw_private *dev_priv) { … } void vmw_fence_manager_takedown(struct vmw_fence_manager *fman) { … } static int vmw_fence_obj_init(struct vmw_fence_manager *fman, struct vmw_fence_obj *fence, u32 seqno, void (*destroy) (struct vmw_fence_obj *fence)) { … } static void vmw_fences_perform_actions(struct vmw_fence_manager *fman, struct list_head *list) { … } /** * vmw_fence_goal_new_locked - Figure out a new device fence goal * seqno if needed. * * @fman: Pointer to a fence manager. * @passed_seqno: The seqno the device currently signals as passed. * * This function should be called with the fence manager lock held. * It is typically called when we have a new passed_seqno, and * we might need to update the fence goal. It checks to see whether * the current fence goal has already passed, and, in that case, * scans through all unsignaled fences to get the next fence object with an * action attached, and sets the seqno of that fence as a new fence goal. * * returns true if the device goal seqno was updated. False otherwise. */ static bool vmw_fence_goal_new_locked(struct vmw_fence_manager *fman, u32 passed_seqno) { … } /** * vmw_fence_goal_check_locked - Replace the device fence goal seqno if * needed. * * @fence: Pointer to a struct vmw_fence_obj the seqno of which should be * considered as a device fence goal. * * This function should be called with the fence manager lock held. * It is typically called when an action has been attached to a fence to * check whether the seqno of that fence should be used for a fence * goal interrupt. This is typically needed if the current fence goal is * invalid, or has a higher seqno than that of the current fence object. * * returns true if the device goal seqno was updated. False otherwise. */ static bool vmw_fence_goal_check_locked(struct vmw_fence_obj *fence) { … } static void __vmw_fences_update(struct vmw_fence_manager *fman) { … } void vmw_fences_update(struct vmw_fence_manager *fman) { … } bool vmw_fence_obj_signaled(struct vmw_fence_obj *fence) { … } int vmw_fence_obj_wait(struct vmw_fence_obj *fence, bool lazy, bool interruptible, unsigned long timeout) { … } static void vmw_fence_destroy(struct vmw_fence_obj *fence) { … } int vmw_fence_create(struct vmw_fence_manager *fman, uint32_t seqno, struct vmw_fence_obj **p_fence) { … } static void vmw_user_fence_destroy(struct vmw_fence_obj *fence) { … } static void vmw_user_fence_base_release(struct ttm_base_object **p_base) { … } int vmw_user_fence_create(struct drm_file *file_priv, struct vmw_fence_manager *fman, uint32_t seqno, struct vmw_fence_obj **p_fence, uint32_t *p_handle) { … } /* * vmw_fence_fifo_down - signal all unsignaled fence objects. */ void vmw_fence_fifo_down(struct vmw_fence_manager *fman) { … } void vmw_fence_fifo_up(struct vmw_fence_manager *fman) { … } /** * vmw_fence_obj_lookup - Look up a user-space fence object * * @tfile: A struct ttm_object_file identifying the caller. * @handle: A handle identifying the fence object. * @return: A struct vmw_user_fence base ttm object on success or * an error pointer on failure. * * The fence object is looked up and type-checked. The caller needs * to have opened the fence object first, but since that happens on * creation and fence objects aren't shareable, that's not an * issue currently. */ static struct ttm_base_object * vmw_fence_obj_lookup(struct ttm_object_file *tfile, u32 handle) { … } int vmw_fence_obj_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { … } int vmw_fence_obj_signaled_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { … } int vmw_fence_obj_unref_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { … } /** * vmw_event_fence_action_seq_passed * * @action: The struct vmw_fence_action embedded in a struct * vmw_event_fence_action. * * This function is called when the seqno of the fence where @action is * attached has passed. It queues the event on the submitter's event list. * This function is always called from atomic context. */ static void vmw_event_fence_action_seq_passed(struct vmw_fence_action *action) { … } /** * vmw_event_fence_action_cleanup * * @action: The struct vmw_fence_action embedded in a struct * vmw_event_fence_action. * * This function is the struct vmw_fence_action destructor. It's typically * called from a workqueue. */ static void vmw_event_fence_action_cleanup(struct vmw_fence_action *action) { … } /** * vmw_fence_obj_add_action - Add an action to a fence object. * * @fence: The fence object. * @action: The action to add. * * Note that the action callbacks may be executed before this function * returns. */ static void vmw_fence_obj_add_action(struct vmw_fence_obj *fence, struct vmw_fence_action *action) { … } /** * vmw_event_fence_action_queue - Post an event for sending when a fence * object seqno has passed. * * @file_priv: The file connection on which the event should be posted. * @fence: The fence object on which to post the event. * @event: Event to be posted. This event should've been alloced * using k[mz]alloc, and should've been completely initialized. * @tv_sec: If non-null, the variable pointed to will be assigned * current time tv_sec val when the fence signals. * @tv_usec: Must be set if @tv_sec is set, and the variable pointed to will * be assigned the current time tv_usec val when the fence signals. * @interruptible: Interruptible waits if possible. * * As a side effect, the object pointed to by @event may have been * freed when this function returns. If this function returns with * an error code, the caller needs to free that object. */ int vmw_event_fence_action_queue(struct drm_file *file_priv, struct vmw_fence_obj *fence, struct drm_pending_event *event, uint32_t *tv_sec, uint32_t *tv_usec, bool interruptible) { … } struct vmw_event_fence_pending { … }; static int vmw_event_fence_action_create(struct drm_file *file_priv, struct vmw_fence_obj *fence, uint32_t flags, uint64_t user_data, bool interruptible) { … } int vmw_fence_event_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { … }