blob: c35c569fa3f072ba24949b1310e50151318c3525 [file] [log] [blame]
/**************************************************************************
*
* 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