| /************************************************************************** |
| * |
| * Copyright (c) 2006-2008 Tungsten Graphics, Inc., Cedar Park, TX., USA |
| * All Rights Reserved. |
| * Copyright (c) 2009 VMware, Inc., Palo Alto, CA., USA |
| * All Rights Reserved. |
| * |
| * This program is free software; you can redistribute it and/or modify it |
| * under the terms and conditions of the GNU General Public License, |
| * version 2, as published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| * more details. |
| * |
| * You should have received a copy of the GNU General Public License along with |
| * this program; if not, write to the Free Software Foundation, Inc., |
| * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| **************************************************************************/ |
| /* |
| * Authors: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> |
| */ |
| #ifndef _TTM_FENCE_DRIVER_H_ |
| #define _TTM_FENCE_DRIVER_H_ |
| |
| #include <linux/kref.h> |
| #include <linux/spinlock.h> |
| #include <linux/wait.h> |
| #include "psb_ttm_fence_api.h" |
| #include "ttm/ttm_memory.h" |
| |
| /** @file ttm_fence_driver.h |
| * |
| * Definitions needed for a driver implementing the |
| * ttm_fence subsystem. |
| */ |
| |
| /** |
| * struct ttm_fence_class_manager: |
| * |
| * @wrap_diff: Sequence difference to catch 32-bit wrapping. |
| * if (seqa - seqb) > @wrap_diff, then seqa < seqb. |
| * @flush_diff: Sequence difference to trigger fence flush. |
| * if (cur_seq - seqa) > @flush_diff, then consider fence object with |
| * seqa as old an needing a flush. |
| * @sequence_mask: Mask of valid bits in a fence sequence. |
| * @lock: Lock protecting this struct as well as fence objects |
| * associated with this struct. |
| * @ring: Circular sequence-ordered list of fence objects. |
| * @pending_flush: Fence types currently needing a flush. |
| * @waiting_types: Fence types that are currently waited for. |
| * @fence_queue: Queue of waiters on fences belonging to this fence class. |
| * @highest_waiting_sequence: Sequence number of the fence with highest |
| * sequence number and that is waited for. |
| * @latest_queued_sequence: Sequence number of the fence latest queued |
| * on the ring. |
| */ |
| |
| struct ttm_fence_class_manager { |
| |
| /* |
| * Unprotected constant members. |
| */ |
| |
| uint32_t wrap_diff; |
| uint32_t flush_diff; |
| uint32_t sequence_mask; |
| |
| /* |
| * The rwlock protects this structure as well as |
| * the data in all fence objects belonging to this |
| * class. This should be OK as most fence objects are |
| * only read from once they're created. |
| */ |
| |
| rwlock_t lock; |
| struct list_head ring; |
| uint32_t pending_flush; |
| uint32_t waiting_types; |
| wait_queue_head_t fence_queue; |
| uint32_t highest_waiting_sequence; |
| uint32_t latest_queued_sequence; |
| }; |
| |
| /** |
| * struct ttm_fence_device |
| * |
| * @fence_class: Array of fence class managers. |
| * @num_classes: Array dimension of @fence_class. |
| * @count: Current number of fence objects for statistics. |
| * @driver: Driver struct. |
| * |
| * Provided in the driver interface so that the driver can derive |
| * from this struct for its driver_private, and accordingly |
| * access the driver_private from the fence driver callbacks. |
| * |
| * All members except "count" are initialized at creation and |
| * never touched after that. No protection needed. |
| * |
| * This struct is private to the fence implementation and to the fence |
| * driver callbacks, and may otherwise be used by drivers only to |
| * obtain the derived device_private object using container_of(). |
| */ |
| |
| struct ttm_fence_device { |
| struct ttm_mem_global *mem_glob; |
| struct ttm_fence_class_manager *fence_class; |
| uint32_t num_classes; |
| atomic_t count; |
| const struct ttm_fence_driver *driver; |
| }; |
| |
| /** |
| * struct ttm_fence_class_init |
| * |
| * @wrap_diff: Fence sequence number wrap indicator. If |
| * (sequence1 - sequence2) > @wrap_diff, then sequence1 is |
| * considered to be older than sequence2. |
| * @flush_diff: Fence sequence number flush indicator. |
| * If a non-completely-signaled fence has a fence sequence number |
| * sequence1 and (sequence1 - current_emit_sequence) > @flush_diff, |
| * the fence is considered too old and it will be flushed upon the |
| * next call of ttm_fence_flush_old(), to make sure no fences with |
| * stale sequence numbers remains unsignaled. @flush_diff should |
| * be sufficiently less than @wrap_diff. |
| * @sequence_mask: Mask with valid bits of the fence sequence |
| * number set to 1. |
| * |
| * This struct is used as input to ttm_fence_device_init. |
| */ |
| |
| struct ttm_fence_class_init { |
| uint32_t wrap_diff; |
| uint32_t flush_diff; |
| uint32_t sequence_mask; |
| }; |
| |
| /** |
| * struct ttm_fence_driver |
| * |
| * @has_irq: Called by a potential waiter. Should return 1 if a |
| * fence object with indicated parameters is expected to signal |
| * automatically, and 0 if the fence implementation needs to |
| * repeatedly call @poll to make it signal. |
| * @emit: Make sure a fence with the given parameters is |
| * present in the indicated command stream. Return its sequence number |
| * in "breadcrumb". |
| * @poll: Check and report sequences of the given "fence_class" |
| * that have signaled "types" |
| * @flush: Make sure that the types indicated by the bitfield |
| * ttm_fence_class_manager::pending_flush will eventually |
| * signal. These bits have been put together using the |
| * result from the needed_flush function described below. |
| * @needed_flush: Given the fence_class and fence_types indicated by |
| * "fence", and the last received fence sequence of this |
| * fence class, indicate what types need a fence flush to |
| * signal. Return as a bitfield. |
| * @wait: Set to non-NULL if the driver wants to override the fence |
| * wait implementation. Return 0 on success, -EBUSY on failure, |
| * and -ERESTART if interruptible and a signal is pending. |
| * @signaled: Driver callback that is called whenever a |
| * ttm_fence_object::signaled_types has changed status. |
| * This function is called from atomic context, |
| * with the ttm_fence_class_manager::lock held in write mode. |
| * @lockup: Driver callback that is called whenever a wait has exceeded |
| * the lifetime of a fence object. |
| * If there is a GPU lockup, |
| * this function should, if possible, reset the GPU, |
| * call the ttm_fence_handler with an error status, and |
| * return. If no lockup was detected, simply extend the |
| * fence timeout_jiffies and return. The driver might |
| * want to protect the lockup check with a mutex and cache a |
| * non-locked-up status for a while to avoid an excessive |
| * amount of lockup checks from every waiting thread. |
| */ |
| |
| struct ttm_fence_driver { |
| bool (*has_irq) (struct ttm_fence_device *fdev, |
| uint32_t fence_class, uint32_t flags); |
| int (*emit) (struct ttm_fence_device *fdev, |
| uint32_t fence_class, |
| uint32_t flags, |
| uint32_t *breadcrumb, unsigned long *timeout_jiffies); |
| void (*flush) (struct ttm_fence_device *fdev, uint32_t fence_class); |
| void (*poll) (struct ttm_fence_device *fdev, |
| uint32_t fence_class, uint32_t types); |
| uint32_t(*needed_flush) |
| (struct ttm_fence_object *fence); |
| int (*wait) (struct ttm_fence_object *fence, bool lazy, |
| bool interruptible, uint32_t mask); |
| void (*signaled) (struct ttm_fence_object *fence); |
| void (*lockup) (struct ttm_fence_object *fence, uint32_t fence_types); |
| }; |
| |
| /** |
| * function ttm_fence_device_init |
| * |
| * @num_classes: Number of fence classes for this fence implementation. |
| * @mem_global: Pointer to the global memory accounting info. |
| * @fdev: Pointer to an uninitialised struct ttm_fence_device. |
| * @init: Array of initialization info for each fence class. |
| * @replicate_init: Use the first @init initialization info for all classes. |
| * @driver: Driver callbacks. |
| * |
| * Initialize a struct ttm_fence_driver structure. Returns -ENOMEM if |
| * out-of-memory. Otherwise returns 0. |
| */ |
| extern int |
| ttm_fence_device_init(int num_classes, |
| struct ttm_mem_global *mem_glob, |
| struct ttm_fence_device *fdev, |
| const struct ttm_fence_class_init *init, |
| bool replicate_init, |
| const struct ttm_fence_driver *driver); |
| |
| /** |
| * function ttm_fence_device_release |
| * |
| * @fdev: Pointer to the fence device. |
| * |
| * Release all resources held by a fence device. Note that before |
| * this function is called, the caller must have made sure all fence |
| * objects belonging to this fence device are completely signaled. |
| */ |
| |
| extern void ttm_fence_device_release(struct ttm_fence_device *fdev); |
| |
| /** |
| * ttm_fence_handler - the fence handler. |
| * |
| * @fdev: Pointer to the fence device. |
| * @fence_class: Fence class that signals. |
| * @sequence: Signaled sequence. |
| * @type: Types that signal. |
| * @error: Error from the engine. |
| * |
| * This function signals all fences with a sequence previous to the |
| * @sequence argument, and belonging to @fence_class. The signaled fence |
| * types are provided in @type. If error is non-zero, the error member |
| * of the fence with sequence = @sequence is set to @error. This value |
| * may be reported back to user-space, indicating, for example an illegal |
| * 3D command or illegal mpeg data. |
| * |
| * This function is typically called from the driver::poll method when the |
| * command sequence preceding the fence marker has executed. It should be |
| * called with the ttm_fence_class_manager::lock held in write mode and |
| * may be called from interrupt context. |
| */ |
| |
| extern void |
| ttm_fence_handler(struct ttm_fence_device *fdev, |
| uint32_t fence_class, |
| uint32_t sequence, uint32_t type, uint32_t error); |
| |
| /** |
| * ttm_fence_driver_from_dev |
| * |
| * @fdev: The ttm fence device. |
| * |
| * Returns a pointer to the fence driver struct. |
| */ |
| |
| static inline const struct ttm_fence_driver *ttm_fence_driver_from_dev( |
| struct ttm_fence_device *fdev) |
| { |
| return fdev->driver; |
| } |
| |
| /** |
| * ttm_fence_driver |
| * |
| * @fence: Pointer to a ttm fence object. |
| * |
| * Returns a pointer to the fence driver struct. |
| */ |
| |
| static inline const struct ttm_fence_driver *ttm_fence_driver(struct |
| ttm_fence_object |
| *fence) |
| { |
| return ttm_fence_driver_from_dev(fence->fdev); |
| } |
| |
| /** |
| * ttm_fence_fc |
| * |
| * @fence: Pointer to a ttm fence object. |
| * |
| * Returns a pointer to the struct ttm_fence_class_manager for the |
| * fence class of @fence. |
| */ |
| |
| static inline struct ttm_fence_class_manager *ttm_fence_fc(struct |
| ttm_fence_object |
| *fence) |
| { |
| return &fence->fdev->fence_class[fence->fence_class]; |
| } |
| |
| #endif |