/************************************************************************** * * 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 */ #ifndef _TTM_FENCE_DRIVER_H_ #define _TTM_FENCE_DRIVER_H_ #include #include #include #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