diff options
Diffstat (limited to 'include/drm/ttm/ttm_bo_driver.h')
| -rw-r--r-- | include/drm/ttm/ttm_bo_driver.h | 575 | 
1 files changed, 332 insertions, 243 deletions
diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h index 8e0c848326b..a5183da3ef9 100644 --- a/include/drm/ttm/ttm_bo_driver.h +++ b/include/drm/ttm/ttm_bo_driver.h @@ -30,99 +30,59 @@  #ifndef _TTM_BO_DRIVER_H_  #define _TTM_BO_DRIVER_H_ -#include "ttm/ttm_bo_api.h" -#include "ttm/ttm_memory.h" -#include "ttm/ttm_module.h" -#include "drm_mm.h" -#include "drm_global.h" -#include "linux/workqueue.h" -#include "linux/fs.h" -#include "linux/spinlock.h" - -struct ttm_backend; +#include <ttm/ttm_bo_api.h> +#include <ttm/ttm_memory.h> +#include <ttm/ttm_module.h> +#include <ttm/ttm_placement.h> +#include <drm/drm_mm.h> +#include <drm/drm_global.h> +#include <drm/drm_vma_manager.h> +#include <linux/workqueue.h> +#include <linux/fs.h> +#include <linux/spinlock.h> +#include <linux/reservation.h>  struct ttm_backend_func {  	/** -	 * struct ttm_backend_func member populate -	 * -	 * @backend: Pointer to a struct ttm_backend. -	 * @num_pages: Number of pages to populate. -	 * @pages: Array of pointers to ttm pages. -	 * @dummy_read_page: Page to be used instead of NULL pages in the -	 * array @pages. -	 * -	 * Populate the backend with ttm pages. Depending on the backend, -	 * it may or may not copy the @pages array. -	 */ -	int (*populate) (struct ttm_backend *backend, -			 unsigned long num_pages, struct page **pages, -			 struct page *dummy_read_page); -	/** -	 * struct ttm_backend_func member clear -	 * -	 * @backend: Pointer to a struct ttm_backend. -	 * -	 * This is an "unpopulate" function. Release all resources -	 * allocated with populate. -	 */ -	void (*clear) (struct ttm_backend *backend); - -	/**  	 * struct ttm_backend_func member bind  	 * -	 * @backend: Pointer to a struct ttm_backend. +	 * @ttm: Pointer to a struct ttm_tt.  	 * @bo_mem: Pointer to a struct ttm_mem_reg describing the  	 * memory type and location for binding.  	 *  	 * Bind the backend pages into the aperture in the location  	 * indicated by @bo_mem. This function should be able to handle -	 * differences between aperture- and system page sizes. +	 * differences between aperture and system page sizes.  	 */ -	int (*bind) (struct ttm_backend *backend, struct ttm_mem_reg *bo_mem); +	int (*bind) (struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem);  	/**  	 * struct ttm_backend_func member unbind  	 * -	 * @backend: Pointer to a struct ttm_backend. +	 * @ttm: Pointer to a struct ttm_tt.  	 *  	 * Unbind previously bound backend pages. This function should be -	 * able to handle differences between aperture- and system page sizes. +	 * able to handle differences between aperture and system page sizes.  	 */ -	int (*unbind) (struct ttm_backend *backend); +	int (*unbind) (struct ttm_tt *ttm);  	/**  	 * struct ttm_backend_func member destroy  	 * -	 * @backend: Pointer to a struct ttm_backend. +	 * @ttm: Pointer to a struct ttm_tt.  	 * -	 * Destroy the backend. +	 * Destroy the backend. This will be call back from ttm_tt_destroy so +	 * don't call ttm_tt_destroy from the callback or infinite loop.  	 */ -	void (*destroy) (struct ttm_backend *backend); -}; - -/** - * struct ttm_backend - * - * @bdev: Pointer to a struct ttm_bo_device. - * @flags: For driver use. - * @func: Pointer to a struct ttm_backend_func that describes - * the backend methods. - * - */ - -struct ttm_backend { -	struct ttm_bo_device *bdev; -	uint32_t flags; -	struct ttm_backend_func *func; +	void (*destroy) (struct ttm_tt *ttm);  }; -#define TTM_PAGE_FLAG_USER            (1 << 1) -#define TTM_PAGE_FLAG_USER_DIRTY      (1 << 2)  #define TTM_PAGE_FLAG_WRITE           (1 << 3)  #define TTM_PAGE_FLAG_SWAPPED         (1 << 4) -#define TTM_PAGE_FLAG_PERSISTANT_SWAP (1 << 5) +#define TTM_PAGE_FLAG_PERSISTENT_SWAP (1 << 5)  #define TTM_PAGE_FLAG_ZERO_ALLOC      (1 << 6)  #define TTM_PAGE_FLAG_DMA32           (1 << 7) +#define TTM_PAGE_FLAG_SG              (1 << 8)  enum ttm_caching_state {  	tt_uncached, @@ -133,19 +93,15 @@ enum ttm_caching_state {  /**   * struct ttm_tt   * + * @bdev: Pointer to a struct ttm_bo_device. + * @func: Pointer to a struct ttm_backend_func that describes + * the backend methods.   * @dummy_read_page: Page to map where the ttm_tt page array contains a NULL   * pointer.   * @pages: Array of pages backing the data. - * @first_himem_page: Himem pages are put last in the page array, which - * enables us to run caching attribute changes on only the first part - * of the page array containing lomem pages. This is the index of the - * first himem page. - * @last_lomem_page: Index of the last lomem page in the page array.   * @num_pages: Number of pages in the page array.   * @bdev: Pointer to the current struct ttm_bo_device.   * @be: Pointer to the ttm backend. - * @tsk: The task for user ttm. - * @start: virtual address for user ttm.   * @swap_storage: Pointer to shmem struct file for swap storage.   * @caching_state: The current caching state of the pages.   * @state: The current binding state of the pages. @@ -156,16 +112,14 @@ enum ttm_caching_state {   */  struct ttm_tt { +	struct ttm_bo_device *bdev; +	struct ttm_backend_func *func;  	struct page *dummy_read_page;  	struct page **pages; -	long first_himem_page; -	long last_lomem_page;  	uint32_t page_flags;  	unsigned long num_pages; +	struct sg_table *sg; /* for SG objects via dma-buf */  	struct ttm_bo_global *glob; -	struct ttm_backend *be; -	struct task_struct *tsk; -	unsigned long start;  	struct file *swap_storage;  	enum ttm_caching_state caching_state;  	enum { @@ -175,33 +129,26 @@ struct ttm_tt {  	} state;  }; -#define TTM_MEMTYPE_FLAG_FIXED         (1 << 0)	/* Fixed (on-card) PCI memory */ -#define TTM_MEMTYPE_FLAG_MAPPABLE      (1 << 1)	/* Memory mappable */ -#define TTM_MEMTYPE_FLAG_CMA           (1 << 3)	/* Can't map aperture */ -  /** - * struct ttm_mem_type_manager + * struct ttm_dma_tt   * - * @has_type: The memory type has been initialized. - * @use_type: The memory type is enabled. - * @flags: TTM_MEMTYPE_XX flags identifying the traits of the memory - * managed by this memory type. - * @gpu_offset: If used, the GPU offset of the first managed page of - * fixed memory or the first managed location in an aperture. - * @size: Size of the managed region. - * @available_caching: A mask of available caching types, TTM_PL_FLAG_XX, - * as defined in ttm_placement_common.h - * @default_caching: The default caching policy used for a buffer object - * placed in this memory type if the user doesn't provide one. - * @manager: The range manager used for this memory type. FIXME: If the aperture - * has a page size different from the underlying system, the granularity - * of this manager should take care of this. But the range allocating code - * in ttm_bo.c needs to be modified for this. - * @lru: The lru list for this memory type. + * @ttm: Base ttm_tt struct. + * @dma_address: The DMA (bus) addresses of the pages + * @pages_list: used by some page allocation backend   * - * This structure is used to identify and manage memory types for a device. - * It's set up by the ttm_bo_driver::init_mem_type method. + * This is a structure holding the pages, caching- and aperture binding + * status for a buffer object that isn't backed by fixed (VRAM / AGP) + * memory.   */ +struct ttm_dma_tt { +	struct ttm_tt ttm; +	dma_addr_t *dma_address; +	struct list_head pages_list; +}; + +#define TTM_MEMTYPE_FLAG_FIXED         (1 << 0)	/* Fixed (on-card) PCI memory */ +#define TTM_MEMTYPE_FLAG_MAPPABLE      (1 << 1)	/* Memory mappable */ +#define TTM_MEMTYPE_FLAG_CMA           (1 << 3)	/* Can't map aperture */  struct ttm_mem_type_manager; @@ -243,9 +190,9 @@ struct ttm_mem_type_manager_func {  	 * @mem::mm_node should be set to a non-null value, and  	 * @mem::start should be set to a value identifying the beginning  	 * of the range allocated, and the function should return zero. -	 * If the memory region accomodate the buffer object, @mem::mm_node +	 * If the memory region accommodate the buffer object, @mem::mm_node  	 * should be set to NULL, and the function should return 0. -	 * If a system error occured, preventing the request to be fulfilled, +	 * If a system error occurred, preventing the request to be fulfilled,  	 * the function should return a negative error code.  	 *  	 * Note that @mem::mm_node will only be dereferenced by @@ -287,6 +234,36 @@ struct ttm_mem_type_manager_func {  	void (*debug)(struct ttm_mem_type_manager *man, const char *prefix);  }; +/** + * struct ttm_mem_type_manager + * + * @has_type: The memory type has been initialized. + * @use_type: The memory type is enabled. + * @flags: TTM_MEMTYPE_XX flags identifying the traits of the memory + * managed by this memory type. + * @gpu_offset: If used, the GPU offset of the first managed page of + * fixed memory or the first managed location in an aperture. + * @size: Size of the managed region. + * @available_caching: A mask of available caching types, TTM_PL_FLAG_XX, + * as defined in ttm_placement_common.h + * @default_caching: The default caching policy used for a buffer object + * placed in this memory type if the user doesn't provide one. + * @func: structure pointer implementing the range manager. See above + * @priv: Driver private closure for @func. + * @io_reserve_mutex: Mutex optionally protecting shared io_reserve structures + * @use_io_reserve_lru: Use an lru list to try to unreserve io_mem_regions + * reserved by the TTM vm system. + * @io_reserve_lru: Optional lru list for unreserving io mem regions. + * @io_reserve_fastpath: Only use bdev::driver::io_mem_reserve to obtain + * static information. bdev::driver::io_mem_free is never used. + * @lru: The lru list for this memory type. + * + * This structure is used to identify and manage memory types for a device. + * It's set up by the ttm_bo_driver::init_mem_type method. + */ + + +  struct ttm_mem_type_manager {  	struct ttm_bo_device *bdev; @@ -303,6 +280,15 @@ struct ttm_mem_type_manager {  	uint32_t default_caching;  	const struct ttm_mem_type_manager_func *func;  	void *priv; +	struct mutex io_reserve_mutex; +	bool use_io_reserve_lru; +	bool io_reserve_fastpath; + +	/* +	 * Protected by @io_reserve_mutex: +	 */ + +	struct list_head io_reserve_lru;  	/*  	 * Protected by the global->lru_lock. @@ -332,15 +318,42 @@ struct ttm_mem_type_manager {  struct ttm_bo_driver {  	/** -	 * struct ttm_bo_driver member create_ttm_backend_entry +	 * ttm_tt_create  	 * -	 * @bdev: The buffer object device. +	 * @bdev: pointer to a struct ttm_bo_device: +	 * @size: Size of the data needed backing. +	 * @page_flags: Page flags as identified by TTM_PAGE_FLAG_XX flags. +	 * @dummy_read_page: See struct ttm_bo_device.  	 * -	 * Create a driver specific struct ttm_backend. +	 * Create a struct ttm_tt to back data with system memory pages. +	 * No pages are actually allocated. +	 * Returns: +	 * NULL: Out of memory.  	 */ +	struct ttm_tt *(*ttm_tt_create)(struct ttm_bo_device *bdev, +					unsigned long size, +					uint32_t page_flags, +					struct page *dummy_read_page); -	struct ttm_backend *(*create_ttm_backend_entry) -	 (struct ttm_bo_device *bdev); +	/** +	 * ttm_tt_populate +	 * +	 * @ttm: The struct ttm_tt to contain the backing pages. +	 * +	 * Allocate all backing pages +	 * Returns: +	 * -ENOMEM: Out of memory. +	 */ +	int (*ttm_tt_populate)(struct ttm_tt *ttm); + +	/** +	 * ttm_tt_unpopulate +	 * +	 * @ttm: The struct ttm_tt to contain the backing pages. +	 * +	 * Free all backing page +	 */ +	void (*ttm_tt_unpopulate)(struct ttm_tt *ttm);  	/**  	 * struct ttm_bo_driver member invalidate_caches @@ -384,7 +397,7 @@ struct ttm_bo_driver {  	 */  	int (*move) (struct ttm_buffer_object *bo,  		     bool evict, bool interruptible, -		     bool no_wait_reserve, bool no_wait_gpu, +		     bool no_wait_gpu,  		     struct ttm_mem_reg *new_mem);  	/** @@ -412,10 +425,10 @@ struct ttm_bo_driver {  	 * documentation.  	 */ -	bool (*sync_obj_signaled) (void *sync_obj, void *sync_arg); -	int (*sync_obj_wait) (void *sync_obj, void *sync_arg, +	bool (*sync_obj_signaled) (void *sync_obj); +	int (*sync_obj_wait) (void *sync_obj,  			      bool lazy, bool interruptible); -	int (*sync_obj_flush) (void *sync_obj, void *sync_arg); +	int (*sync_obj_flush) (void *sync_obj);  	void (*sync_obj_unref) (void **sync_obj);  	void *(*sync_obj_ref) (void *sync_obj); @@ -458,9 +471,6 @@ struct ttm_bo_global_ref {   * @dummy_read_page: Pointer to a dummy page used for mapping requests   * of unpopulated pages.   * @shrink: A shrink callback object used for buffer object swap. - * @ttm_bo_extra_size: Extra size (sizeof(struct ttm_buffer_object) excluded) - * used by a buffer object. This is excluding page arrays and backing pages. - * @ttm_bo_size: This is @ttm_bo_extra_size + sizeof(struct ttm_buffer_object).   * @device_list_mutex: Mutex protecting the device list.   * This mutex is held while traversing the device list for pm options.   * @lru_lock: Spinlock protecting the bo subsystem lru lists. @@ -478,8 +488,6 @@ struct ttm_bo_global {  	struct ttm_mem_global *mem_glob;  	struct page *dummy_read_page;  	struct ttm_mem_shrink shrink; -	size_t ttm_bo_extra_size; -	size_t ttm_bo_size;  	struct mutex device_list_mutex;  	spinlock_t lru_lock; @@ -510,11 +518,12 @@ struct ttm_bo_global {   *   * @driver: Pointer to a struct ttm_bo_driver struct setup by the driver.   * @man: An array of mem_type_managers. - * @addr_space_mm: Range manager for the device address space. + * @fence_lock: Protects the synchronizing members on *all* bos belonging + * to this device. + * @vma_manager: Address space manager   * lru_lock: Spinlock that protects the buffer+device lru lists and   * ddestroy lists. - * @nice_mode: Try nicely to wait for buffer idle when cleaning a manager. - * If a GPU lockup has been detected, this is forced to 0. + * @val_seq: Current validation sequence.   * @dev_mapping: A pointer to the struct address_space representing the   * device address space.   * @wq: Work queue structure for the delayed delete workqueue. @@ -529,24 +538,24 @@ struct ttm_bo_device {  	struct list_head device_list;  	struct ttm_bo_global *glob;  	struct ttm_bo_driver *driver; -	rwlock_t vm_lock;  	struct ttm_mem_type_manager man[TTM_NUM_MEM_TYPES]; +	spinlock_t fence_lock; +  	/* -	 * Protected by the vm lock. +	 * Protected by internal locks.  	 */ -	struct rb_root addr_space_rb; -	struct drm_mm addr_space_mm; +	struct drm_vma_offset_manager vma_manager;  	/*  	 * Protected by the global:lru lock.  	 */  	struct list_head ddestroy; +	uint32_t val_seq;  	/*  	 * Protected by load / firstopen / lastclose /unload sync.  	 */ -	bool nice_mode;  	struct address_space *dev_mapping;  	/* @@ -576,8 +585,9 @@ ttm_flag_masked(uint32_t *old, uint32_t new, uint32_t mask)  }  /** - * ttm_tt_create + * ttm_tt_init   * + * @ttm: The struct ttm_tt.   * @bdev: pointer to a struct ttm_bo_device:   * @size: Size of the data needed backing.   * @page_flags: Page flags as identified by TTM_PAGE_FLAG_XX flags. @@ -588,28 +598,22 @@ ttm_flag_masked(uint32_t *old, uint32_t new, uint32_t mask)   * Returns:   * NULL: Out of memory.   */ -extern struct ttm_tt *ttm_tt_create(struct ttm_bo_device *bdev, -				    unsigned long size, -				    uint32_t page_flags, -				    struct page *dummy_read_page); +extern int ttm_tt_init(struct ttm_tt *ttm, struct ttm_bo_device *bdev, +			unsigned long size, uint32_t page_flags, +			struct page *dummy_read_page); +extern int ttm_dma_tt_init(struct ttm_dma_tt *ttm_dma, struct ttm_bo_device *bdev, +			   unsigned long size, uint32_t page_flags, +			   struct page *dummy_read_page);  /** - * ttm_tt_set_user: + * ttm_tt_fini   * - * @ttm: The struct ttm_tt to populate. - * @tsk: A struct task_struct for which @start is a valid user-space address. - * @start: A valid user-space address. - * @num_pages: Size in pages of the user memory area. + * @ttm: the ttm_tt structure.   * - * Populate a struct ttm_tt with a user-space memory area after first pinning - * the pages backing it. - * Returns: - * !0: Error. + * Free memory of ttm_tt structure   */ - -extern int ttm_tt_set_user(struct ttm_tt *ttm, -			   struct task_struct *tsk, -			   unsigned long start, unsigned long num_pages); +extern void ttm_tt_fini(struct ttm_tt *ttm); +extern void ttm_dma_tt_fini(struct ttm_dma_tt *ttm_dma);  /**   * ttm_ttm_bind: @@ -622,20 +626,11 @@ extern int ttm_tt_set_user(struct ttm_tt *ttm,  extern int ttm_tt_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem);  /** - * ttm_tt_populate: - * - * @ttm: The struct ttm_tt to contain the backing pages. - * - * Add backing pages to all of @ttm - */ -extern int ttm_tt_populate(struct ttm_tt *ttm); - -/**   * ttm_ttm_destroy:   *   * @ttm: The struct ttm_tt.   * - * Unbind, unpopulate and destroy a struct ttm_tt. + * Unbind, unpopulate and destroy common struct ttm_tt.   */  extern void ttm_tt_destroy(struct ttm_tt *ttm); @@ -649,19 +644,13 @@ extern void ttm_tt_destroy(struct ttm_tt *ttm);  extern void ttm_tt_unbind(struct ttm_tt *ttm);  /** - * ttm_ttm_destroy: + * ttm_tt_swapin:   *   * @ttm: The struct ttm_tt. - * @index: Index of the desired page.   * - * Return a pointer to the struct page backing @ttm at page - * index @index. If the page is unpopulated, one will be allocated to - * populate that index. - * - * Returns: - * NULL on OOM. + * Swap in a previously swap out ttm_tt.   */ -extern struct page *ttm_tt_get_page(struct ttm_tt *ttm, int index); +extern int ttm_tt_swapin(struct ttm_tt *ttm);  /**   * ttm_tt_cache_flush: @@ -690,7 +679,16 @@ extern void ttm_tt_cache_flush(struct page *pages[], unsigned long num_pages);   */  extern int ttm_tt_set_placement_caching(struct ttm_tt *ttm, uint32_t placement);  extern int ttm_tt_swapout(struct ttm_tt *ttm, -			  struct file *persistant_swap_storage); +			  struct file *persistent_swap_storage); + +/** + * ttm_tt_unpopulate - free pages from a ttm + * + * @ttm: Pointer to the ttm_tt structure + * + * Calls the driver method to free all pages from a ttm + */ +extern void ttm_tt_unpopulate(struct ttm_tt *ttm);  /*   * ttm_bo.c @@ -716,7 +714,6 @@ extern bool ttm_mem_reg_is_pci(struct ttm_bo_device *bdev,   * @proposed_placement: Proposed new placement for the buffer object.   * @mem: A struct ttm_mem_reg.   * @interruptible: Sleep interruptible when sliping. - * @no_wait_reserve: Return immediately if other buffers are busy.   * @no_wait_gpu: Return immediately if the GPU is busy.   *   * Allocate memory space for the buffer object pointed to by @bo, using @@ -732,52 +729,13 @@ extern int ttm_bo_mem_space(struct ttm_buffer_object *bo,  				struct ttm_placement *placement,  				struct ttm_mem_reg *mem,  				bool interruptible, -				bool no_wait_reserve, bool no_wait_gpu); +				bool no_wait_gpu);  extern void ttm_bo_mem_put(struct ttm_buffer_object *bo,  			   struct ttm_mem_reg *mem);  extern void ttm_bo_mem_put_locked(struct ttm_buffer_object *bo,  				  struct ttm_mem_reg *mem); -/** - * ttm_bo_wait_for_cpu - * - * @bo: Pointer to a struct ttm_buffer_object. - * @no_wait: Don't sleep while waiting. - * - * Wait until a buffer object is no longer sync'ed for CPU access. - * Returns: - * -EBUSY: Buffer object was sync'ed for CPU access. (only if no_wait == 1). - * -ERESTARTSYS: An interruptible sleep was interrupted by a signal. - */ - -extern int ttm_bo_wait_cpu(struct ttm_buffer_object *bo, bool no_wait); - -/** - * ttm_bo_pci_offset - Get the PCI offset for the buffer object memory. - * - * @bo Pointer to a struct ttm_buffer_object. - * @bus_base On return the base of the PCI region - * @bus_offset On return the byte offset into the PCI region - * @bus_size On return the byte size of the buffer object or zero if - * the buffer object memory is not accessible through a PCI region. - * - * Returns: - * -EINVAL if the buffer object is currently not mappable. - * 0 otherwise. - */ - -extern int ttm_bo_pci_offset(struct ttm_bo_device *bdev, -			     struct ttm_mem_reg *mem, -			     unsigned long *bus_base, -			     unsigned long *bus_offset, -			     unsigned long *bus_size); - -extern int ttm_mem_io_reserve(struct ttm_bo_device *bdev, -				struct ttm_mem_reg *mem); -extern void ttm_mem_io_free(struct ttm_bo_device *bdev, -				struct ttm_mem_reg *mem); -  extern void ttm_bo_global_release(struct drm_global_reference *ref);  extern int ttm_bo_global_init(struct drm_global_reference *ref); @@ -787,8 +745,9 @@ extern int ttm_bo_device_release(struct ttm_bo_device *bdev);   * ttm_bo_device_init   *   * @bdev: A pointer to a struct ttm_bo_device to initialize. - * @mem_global: A pointer to an initialized struct ttm_mem_global. + * @glob: A pointer to an initialized struct ttm_bo_global.   * @driver: A pointer to a struct ttm_bo_driver set up by the caller. + * @mapping: The address space to use for this bo.   * @file_page_offset: Offset into the device address space that is available   * for buffer data. This ensures compatibility with other users of the   * address space. @@ -800,6 +759,7 @@ extern int ttm_bo_device_release(struct ttm_bo_device *bdev);  extern int ttm_bo_device_init(struct ttm_bo_device *bdev,  			      struct ttm_bo_global *glob,  			      struct ttm_bo_driver *driver, +			      struct address_space *mapping,  			      uint64_t file_page_offset, bool need_dma32);  /** @@ -810,13 +770,78 @@ extern int ttm_bo_device_init(struct ttm_bo_device *bdev,  extern void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo);  /** + * ttm_bo_unmap_virtual + * + * @bo: tear down the virtual mappings for this BO + * + * The caller must take ttm_mem_io_lock before calling this function. + */ +extern void ttm_bo_unmap_virtual_locked(struct ttm_buffer_object *bo); + +extern int ttm_mem_io_reserve_vm(struct ttm_buffer_object *bo); +extern void ttm_mem_io_free_vm(struct ttm_buffer_object *bo); +extern int ttm_mem_io_lock(struct ttm_mem_type_manager *man, +			   bool interruptible); +extern void ttm_mem_io_unlock(struct ttm_mem_type_manager *man); + +extern void ttm_bo_del_sub_from_lru(struct ttm_buffer_object *bo); +extern void ttm_bo_add_to_lru(struct ttm_buffer_object *bo); + +/** + * __ttm_bo_reserve: + * + * @bo: A pointer to a struct ttm_buffer_object. + * @interruptible: Sleep interruptible if waiting. + * @no_wait: Don't sleep while trying to reserve, rather return -EBUSY. + * @use_ticket: If @bo is already reserved, Only sleep waiting for + * it to become unreserved if @ticket->stamp is older. + * + * Will not remove reserved buffers from the lru lists. + * Otherwise identical to ttm_bo_reserve. + * + * Returns: + * -EDEADLK: The reservation may cause a deadlock. + * Release all buffer reservations, wait for @bo to become unreserved and + * try again. (only if use_sequence == 1). + * -ERESTARTSYS: A wait for the buffer to become unreserved was interrupted by + * a signal. Release all buffer reservations and return to user-space. + * -EBUSY: The function needed to sleep, but @no_wait was true + * -EALREADY: Bo already reserved using @ticket. This error code will only + * be returned if @use_ticket is set to true. + */ +static inline int __ttm_bo_reserve(struct ttm_buffer_object *bo, +				   bool interruptible, +				   bool no_wait, bool use_ticket, +				   struct ww_acquire_ctx *ticket) +{ +	int ret = 0; + +	if (no_wait) { +		bool success; +		if (WARN_ON(ticket)) +			return -EBUSY; + +		success = ww_mutex_trylock(&bo->resv->lock); +		return success ? 0 : -EBUSY; +	} + +	if (interruptible) +		ret = ww_mutex_lock_interruptible(&bo->resv->lock, ticket); +	else +		ret = ww_mutex_lock(&bo->resv->lock, ticket); +	if (ret == -EINTR) +		return -ERESTARTSYS; +	return ret; +} + +/**   * ttm_bo_reserve:   *   * @bo: A pointer to a struct ttm_buffer_object.   * @interruptible: Sleep interruptible if waiting.   * @no_wait: Don't sleep while trying to reserve, rather return -EBUSY. - * @use_sequence: If @bo is already reserved, Only sleep waiting for - * it to become unreserved if @sequence < (@bo)->sequence. + * @use_ticket: If @bo is already reserved, Only sleep waiting for + * it to become unreserved if @ticket->stamp is older.   *   * Locks a buffer object for validation. (Or prevents other processes from   * locking it for validation) and removes it from lru lists, while taking @@ -826,20 +851,11 @@ extern void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo);   * different order, either by will or as a result of a buffer being evicted   * to make room for a buffer already reserved. (Buffers are reserved before   * they are evicted). The following algorithm prevents such deadlocks from - * occuring: - * 1) Buffers are reserved with the lru spinlock held. Upon successful - * reservation they are removed from the lru list. This stops a reserved buffer - * from being evicted. However the lru spinlock is released between the time - * a buffer is selected for eviction and the time it is reserved. - * Therefore a check is made when a buffer is reserved for eviction, that it - * is still the first buffer in the lru list, before it is removed from the - * list. @check_lru == 1 forces this check. If it fails, the function returns - * -EINVAL, and the caller should then choose a new buffer to evict and repeat - * the procedure. - * 2) Processes attempting to reserve multiple buffers other than for eviction, + * occurring: + * Processes attempting to reserve multiple buffers other than for eviction,   * (typically execbuf), should first obtain a unique 32-bit   * validation sequence number, - * and call this function with @use_sequence == 1 and @sequence == the unique + * and call this function with @use_ticket == 1 and @ticket->stamp == the unique   * sequence number. If upon call of this function, the buffer object is already   * reserved, the validation sequence is checked against the validation   * sequence of the process currently reserving the buffer, @@ -854,15 +870,74 @@ extern void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo);   * will eventually succeed, preventing both deadlocks and starvation.   *   * Returns: - * -EAGAIN: The reservation may cause a deadlock. + * -EDEADLK: The reservation may cause a deadlock.   * Release all buffer reservations, wait for @bo to become unreserved and   * try again. (only if use_sequence == 1).   * -ERESTARTSYS: A wait for the buffer to become unreserved was interrupted by   * a signal. Release all buffer reservations and return to user-space. + * -EBUSY: The function needed to sleep, but @no_wait was true + * -EALREADY: Bo already reserved using @ticket. This error code will only + * be returned if @use_ticket is set to true.   */ -extern int ttm_bo_reserve(struct ttm_buffer_object *bo, -			  bool interruptible, -			  bool no_wait, bool use_sequence, uint32_t sequence); +static inline int ttm_bo_reserve(struct ttm_buffer_object *bo, +				 bool interruptible, +				 bool no_wait, bool use_ticket, +				 struct ww_acquire_ctx *ticket) +{ +	int ret; + +	WARN_ON(!atomic_read(&bo->kref.refcount)); + +	ret = __ttm_bo_reserve(bo, interruptible, no_wait, use_ticket, ticket); +	if (likely(ret == 0)) +		ttm_bo_del_sub_from_lru(bo); + +	return ret; +} + +/** + * ttm_bo_reserve_slowpath: + * @bo: A pointer to a struct ttm_buffer_object. + * @interruptible: Sleep interruptible if waiting. + * @sequence: Set (@bo)->sequence to this value after lock + * + * This is called after ttm_bo_reserve returns -EAGAIN and we backed off + * from all our other reservations. Because there are no other reservations + * held by us, this function cannot deadlock any more. + */ +static inline int ttm_bo_reserve_slowpath(struct ttm_buffer_object *bo, +					  bool interruptible, +					  struct ww_acquire_ctx *ticket) +{ +	int ret = 0; + +	WARN_ON(!atomic_read(&bo->kref.refcount)); + +	if (interruptible) +		ret = ww_mutex_lock_slow_interruptible(&bo->resv->lock, +						       ticket); +	else +		ww_mutex_lock_slow(&bo->resv->lock, ticket); + +	if (likely(ret == 0)) +		ttm_bo_del_sub_from_lru(bo); +	else if (ret == -EINTR) +		ret = -ERESTARTSYS; + +	return ret; +} + +/** + * __ttm_bo_unreserve + * @bo: A pointer to a struct ttm_buffer_object. + * + * Unreserve a previous reservation of @bo where the buffer object is + * already on lru lists. + */ +static inline void __ttm_bo_unreserve(struct ttm_buffer_object *bo) +{ +	ww_mutex_unlock(&bo->resv->lock); +}  /**   * ttm_bo_unreserve @@ -871,30 +946,42 @@ extern int ttm_bo_reserve(struct ttm_buffer_object *bo,   *   * Unreserve a previous reservation of @bo.   */ -extern void ttm_bo_unreserve(struct ttm_buffer_object *bo); +static inline void ttm_bo_unreserve(struct ttm_buffer_object *bo) +{ +	if (!(bo->mem.placement & TTM_PL_FLAG_NO_EVICT)) { +		spin_lock(&bo->glob->lru_lock); +		ttm_bo_add_to_lru(bo); +		spin_unlock(&bo->glob->lru_lock); +	} +	__ttm_bo_unreserve(bo); +}  /** - * ttm_bo_wait_unreserved - * + * ttm_bo_unreserve_ticket   * @bo: A pointer to a struct ttm_buffer_object. + * @ticket: ww_acquire_ctx used for reserving   * - * Wait for a struct ttm_buffer_object to become unreserved. - * This is typically used in the execbuf code to relax cpu-usage when - * a potential deadlock condition backoff. + * Unreserve a previous reservation of @bo made with @ticket.   */ -extern int ttm_bo_wait_unreserved(struct ttm_buffer_object *bo, -				  bool interruptible); +static inline void ttm_bo_unreserve_ticket(struct ttm_buffer_object *bo, +					   struct ww_acquire_ctx *t) +{ +	ttm_bo_unreserve(bo); +}  /*   * ttm_bo_util.c   */ +int ttm_mem_io_reserve(struct ttm_bo_device *bdev, +		       struct ttm_mem_reg *mem); +void ttm_mem_io_free(struct ttm_bo_device *bdev, +		     struct ttm_mem_reg *mem);  /**   * ttm_bo_move_ttm   *   * @bo: A pointer to a struct ttm_buffer_object.   * @evict: 1: This is an eviction. Don't try to pipeline. - * @no_wait_reserve: Return immediately if other buffers are busy.   * @no_wait_gpu: Return immediately if the GPU is busy.   * @new_mem: struct ttm_mem_reg indicating where to move.   * @@ -909,15 +996,14 @@ extern int ttm_bo_wait_unreserved(struct ttm_buffer_object *bo,   */  extern int ttm_bo_move_ttm(struct ttm_buffer_object *bo, -			   bool evict, bool no_wait_reserve, -			   bool no_wait_gpu, struct ttm_mem_reg *new_mem); +			   bool evict, bool no_wait_gpu, +			   struct ttm_mem_reg *new_mem);  /**   * ttm_bo_move_memcpy   *   * @bo: A pointer to a struct ttm_buffer_object.   * @evict: 1: This is an eviction. Don't try to pipeline. - * @no_wait_reserve: Return immediately if other buffers are busy.   * @no_wait_gpu: Return immediately if the GPU is busy.   * @new_mem: struct ttm_mem_reg indicating where to move.   * @@ -932,8 +1018,8 @@ extern int ttm_bo_move_ttm(struct ttm_buffer_object *bo,   */  extern int ttm_bo_move_memcpy(struct ttm_buffer_object *bo, -			      bool evict, bool no_wait_reserve, -			      bool no_wait_gpu, struct ttm_mem_reg *new_mem); +			      bool evict, bool no_wait_gpu, +			      struct ttm_mem_reg *new_mem);  /**   * ttm_bo_free_old_node @@ -949,10 +1035,7 @@ extern void ttm_bo_free_old_node(struct ttm_buffer_object *bo);   *   * @bo: A pointer to a struct ttm_buffer_object.   * @sync_obj: A sync object that signals when moving is complete. - * @sync_obj_arg: An argument to pass to the sync object idle / wait - * functions.   * @evict: This is an evict move. Don't return until the buffer is idle. - * @no_wait_reserve: Return immediately if other buffers are busy.   * @no_wait_gpu: Return immediately if the GPU is busy.   * @new_mem: struct ttm_mem_reg indicating where to move.   * @@ -966,9 +1049,7 @@ extern void ttm_bo_free_old_node(struct ttm_buffer_object *bo);  extern int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo,  				     void *sync_obj, -				     void *sync_obj_arg, -				     bool evict, bool no_wait_reserve, -				     bool no_wait_gpu, +				     bool evict, bool no_wait_gpu,  				     struct ttm_mem_reg *new_mem);  /**   * ttm_io_prot @@ -988,17 +1069,25 @@ extern const struct ttm_mem_type_manager_func ttm_bo_manager_func;  #include <linux/agp_backend.h>  /** - * ttm_agp_backend_init + * ttm_agp_tt_create   *   * @bdev: Pointer to a struct ttm_bo_device.   * @bridge: The agp bridge this device is sitting on. + * @size: Size of the data needed backing. + * @page_flags: Page flags as identified by TTM_PAGE_FLAG_XX flags. + * @dummy_read_page: See struct ttm_bo_device. + *   *   * Create a TTM backend that uses the indicated AGP bridge as an aperture   * for TT memory. This function uses the linux agpgart interface to   * bind and unbind memory backing a ttm_tt.   */ -extern struct ttm_backend *ttm_agp_backend_init(struct ttm_bo_device *bdev, -						struct agp_bridge_data *bridge); +extern struct ttm_tt *ttm_agp_tt_create(struct ttm_bo_device *bdev, +					struct agp_bridge_data *bridge, +					unsigned long size, uint32_t page_flags, +					struct page *dummy_read_page); +int ttm_agp_tt_populate(struct ttm_tt *ttm); +void ttm_agp_tt_unpopulate(struct ttm_tt *ttm);  #endif  #endif  | 
