| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright 2007 Dave Airlied | 
					
						
							|  |  |  |  * All Rights Reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 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, sublicense, | 
					
						
							|  |  |  |  * 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 NONINFRINGEMENT.  IN NO EVENT SHALL | 
					
						
							|  |  |  |  * VA LINUX SYSTEMS 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. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Authors: Dave Airlied <airlied@linux.ie> | 
					
						
							|  |  |  |  *	    Ben Skeggs   <darktama@iinet.net.au> | 
					
						
							|  |  |  |  *	    Jeremy Kolb  <jkolb@brandeis.edu> | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | #include <core/engine.h>
 | 
					
						
							| 
									
										
										
										
											2013-02-01 13:44:33 -05:00
										 |  |  | #include <linux/swiotlb.h>
 | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | #include <subdev/fb.h>
 | 
					
						
							|  |  |  | #include <subdev/vm.h>
 | 
					
						
							|  |  |  | #include <subdev/bar.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "nouveau_drm.h"
 | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | #include "nouveau_dma.h"
 | 
					
						
							| 
									
										
										
										
											2012-04-30 13:30:00 +10:00
										 |  |  | #include "nouveau_fence.h"
 | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | #include "nouveau_bo.h"
 | 
					
						
							|  |  |  | #include "nouveau_ttm.h"
 | 
					
						
							|  |  |  | #include "nouveau_gem.h"
 | 
					
						
							| 
									
										
										
										
											2009-12-26 21:46:36 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-19 17:54:21 +10:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * NV10-NV40 tiling helpers | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | nv10_bo_update_tile_region(struct drm_device *dev, struct nouveau_drm_tile *reg, | 
					
						
							|  |  |  | 			   u32 addr, u32 size, u32 pitch, u32 flags) | 
					
						
							| 
									
										
										
										
											2012-07-19 17:54:21 +10:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-07-31 16:16:21 +10:00
										 |  |  | 	struct nouveau_drm *drm = nouveau_drm(dev); | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	int i = reg - drm->tile.reg; | 
					
						
							|  |  |  | 	struct nouveau_fb *pfb = nouveau_fb(drm->device); | 
					
						
							|  |  |  | 	struct nouveau_fb_tile *tile = &pfb->tile.region[i]; | 
					
						
							|  |  |  | 	struct nouveau_engine *engine; | 
					
						
							| 
									
										
										
										
											2012-07-19 17:54:21 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	nouveau_fence_unref(®->fence); | 
					
						
							| 
									
										
										
										
											2012-07-19 17:54:21 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (tile->pitch) | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 		pfb->tile.fini(pfb, i, tile); | 
					
						
							| 
									
										
										
										
											2012-07-19 17:54:21 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (pitch) | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 		pfb->tile.init(pfb, i, addr, size, pitch, flags, tile); | 
					
						
							| 
									
										
										
										
											2012-07-19 17:54:21 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	pfb->tile.prog(pfb, i, tile); | 
					
						
							| 
									
										
										
										
											2012-07-19 17:54:21 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	if ((engine = nouveau_engine(pfb, NVDEV_ENGINE_GR))) | 
					
						
							|  |  |  | 		engine->tile_prog(engine, i); | 
					
						
							|  |  |  | 	if ((engine = nouveau_engine(pfb, NVDEV_ENGINE_MPEG))) | 
					
						
							|  |  |  | 		engine->tile_prog(engine, i); | 
					
						
							| 
									
										
										
										
											2012-07-19 17:54:21 +10:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | static struct nouveau_drm_tile * | 
					
						
							| 
									
										
										
										
											2012-07-19 17:54:21 +10:00
										 |  |  | nv10_bo_get_tile_region(struct drm_device *dev, int i) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-07-31 16:16:21 +10:00
										 |  |  | 	struct nouveau_drm *drm = nouveau_drm(dev); | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	struct nouveau_drm_tile *tile = &drm->tile.reg[i]; | 
					
						
							| 
									
										
										
										
											2012-07-19 17:54:21 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	spin_lock(&drm->tile.lock); | 
					
						
							| 
									
										
										
										
											2012-07-19 17:54:21 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (!tile->used && | 
					
						
							|  |  |  | 	    (!tile->fence || nouveau_fence_done(tile->fence))) | 
					
						
							|  |  |  | 		tile->used = true; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		tile = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	spin_unlock(&drm->tile.lock); | 
					
						
							| 
									
										
										
										
											2012-07-19 17:54:21 +10:00
										 |  |  | 	return tile; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | nv10_bo_put_tile_region(struct drm_device *dev, struct nouveau_drm_tile *tile, | 
					
						
							|  |  |  | 			struct nouveau_fence *fence) | 
					
						
							| 
									
										
										
										
											2012-07-19 17:54:21 +10:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-07-31 16:16:21 +10:00
										 |  |  | 	struct nouveau_drm *drm = nouveau_drm(dev); | 
					
						
							| 
									
										
										
										
											2012-07-19 17:54:21 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (tile) { | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 		spin_lock(&drm->tile.lock); | 
					
						
							| 
									
										
										
										
											2012-07-19 17:54:21 +10:00
										 |  |  | 		if (fence) { | 
					
						
							|  |  |  | 			/* Mark it as pending. */ | 
					
						
							|  |  |  | 			tile->fence = fence; | 
					
						
							|  |  |  | 			nouveau_fence_ref(fence); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		tile->used = false; | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 		spin_unlock(&drm->tile.lock); | 
					
						
							| 
									
										
										
										
											2012-07-19 17:54:21 +10:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | static struct nouveau_drm_tile * | 
					
						
							|  |  |  | nv10_bo_set_tiling(struct drm_device *dev, u32 addr, | 
					
						
							|  |  |  | 		   u32 size, u32 pitch, u32 flags) | 
					
						
							| 
									
										
										
										
											2012-07-19 17:54:21 +10:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-07-31 16:16:21 +10:00
										 |  |  | 	struct nouveau_drm *drm = nouveau_drm(dev); | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	struct nouveau_fb *pfb = nouveau_fb(drm->device); | 
					
						
							|  |  |  | 	struct nouveau_drm_tile *tile, *found = NULL; | 
					
						
							| 
									
										
										
										
											2012-07-19 17:54:21 +10:00
										 |  |  | 	int i; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	for (i = 0; i < pfb->tile.regions; i++) { | 
					
						
							| 
									
										
										
										
											2012-07-19 17:54:21 +10:00
										 |  |  | 		tile = nv10_bo_get_tile_region(dev, i); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (pitch && !found) { | 
					
						
							|  |  |  | 			found = tile; | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 		} else if (tile && pfb->tile.region[i].pitch) { | 
					
						
							| 
									
										
										
										
											2012-07-19 17:54:21 +10:00
										 |  |  | 			/* Kill an unused tile region. */ | 
					
						
							|  |  |  | 			nv10_bo_update_tile_region(dev, tile, 0, 0, 0, 0); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		nv10_bo_put_tile_region(dev, tile, NULL); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (found) | 
					
						
							|  |  |  | 		nv10_bo_update_tile_region(dev, found, addr, size, | 
					
						
							|  |  |  | 					    pitch, flags); | 
					
						
							|  |  |  | 	return found; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | static void | 
					
						
							|  |  |  | nouveau_bo_del_ttm(struct ttm_buffer_object *bo) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	struct nouveau_drm *drm = nouveau_bdev(bo->bdev); | 
					
						
							|  |  |  | 	struct drm_device *dev = drm->dev; | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 	struct nouveau_bo *nvbo = nouveau_bo(bo); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (unlikely(nvbo->gem)) | 
					
						
							|  |  |  | 		DRM_ERROR("bo %p still attached to GEM object\n", bo); | 
					
						
							| 
									
										
										
										
											2012-07-19 17:54:21 +10:00
										 |  |  | 	nv10_bo_put_tile_region(dev, nvbo->tile, NULL); | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 	kfree(nvbo); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-11 16:51:09 +01:00
										 |  |  | static void | 
					
						
							| 
									
										
										
										
											2011-02-10 13:41:01 +10:00
										 |  |  | nouveau_bo_fixup_align(struct nouveau_bo *nvbo, u32 flags, | 
					
						
							| 
									
										
										
										
											2011-06-06 14:15:46 +10:00
										 |  |  | 		       int *align, int *size) | 
					
						
							| 
									
										
										
										
											2009-12-11 16:51:09 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev); | 
					
						
							|  |  |  | 	struct nouveau_device *device = nv_device(drm->device); | 
					
						
							| 
									
										
										
										
											2009-12-11 16:51:09 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	if (device->card_type < NV_50) { | 
					
						
							| 
									
										
										
										
											2010-11-12 15:12:51 +10:00
										 |  |  | 		if (nvbo->tile_mode) { | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 			if (device->chipset >= 0x40) { | 
					
						
							| 
									
										
										
										
											2009-12-11 16:51:09 +01:00
										 |  |  | 				*align = 65536; | 
					
						
							| 
									
										
										
										
											2010-11-12 15:12:51 +10:00
										 |  |  | 				*size = roundup(*size, 64 * nvbo->tile_mode); | 
					
						
							| 
									
										
										
										
											2009-12-11 16:51:09 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 			} else if (device->chipset >= 0x30) { | 
					
						
							| 
									
										
										
										
											2009-12-11 16:51:09 +01:00
										 |  |  | 				*align = 32768; | 
					
						
							| 
									
										
										
										
											2010-11-12 15:12:51 +10:00
										 |  |  | 				*size = roundup(*size, 64 * nvbo->tile_mode); | 
					
						
							| 
									
										
										
										
											2009-12-11 16:51:09 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 			} else if (device->chipset >= 0x20) { | 
					
						
							| 
									
										
										
										
											2009-12-11 16:51:09 +01:00
										 |  |  | 				*align = 16384; | 
					
						
							| 
									
										
										
										
											2010-11-12 15:12:51 +10:00
										 |  |  | 				*size = roundup(*size, 64 * nvbo->tile_mode); | 
					
						
							| 
									
										
										
										
											2009-12-11 16:51:09 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 			} else if (device->chipset >= 0x10) { | 
					
						
							| 
									
										
										
										
											2009-12-11 16:51:09 +01:00
										 |  |  | 				*align = 16384; | 
					
						
							| 
									
										
										
										
											2010-11-12 15:12:51 +10:00
										 |  |  | 				*size = roundup(*size, 32 * nvbo->tile_mode); | 
					
						
							| 
									
										
										
										
											2009-12-11 16:51:09 +01:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2010-11-12 15:12:51 +10:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2011-06-06 14:15:46 +10:00
										 |  |  | 		*size = roundup(*size, (1 << nvbo->page_shift)); | 
					
						
							|  |  |  | 		*align = max((1 <<  nvbo->page_shift), *align); | 
					
						
							| 
									
										
										
										
											2009-12-11 16:51:09 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-25 18:51:17 +01:00
										 |  |  | 	*size = roundup(*size, PAGE_SIZE); | 
					
						
							| 
									
										
										
										
											2009-12-11 16:51:09 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | int | 
					
						
							| 
									
										
										
										
											2011-06-07 14:21:29 +10:00
										 |  |  | nouveau_bo_new(struct drm_device *dev, int size, int align, | 
					
						
							|  |  |  | 	       uint32_t flags, uint32_t tile_mode, uint32_t tile_flags, | 
					
						
							| 
									
										
										
										
											2012-04-02 11:53:06 +01:00
										 |  |  | 	       struct sg_table *sg, | 
					
						
							| 
									
										
										
										
											2011-06-07 14:21:29 +10:00
										 |  |  | 	       struct nouveau_bo **pnvbo) | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-07-31 16:16:21 +10:00
										 |  |  | 	struct nouveau_drm *drm = nouveau_drm(dev); | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 	struct nouveau_bo *nvbo; | 
					
						
							| 
									
										
										
										
											2011-11-11 15:42:57 -05:00
										 |  |  | 	size_t acc_size; | 
					
						
							| 
									
										
										
										
											2011-06-06 14:15:46 +10:00
										 |  |  | 	int ret; | 
					
						
							| 
									
										
										
										
											2012-04-02 11:53:06 +01:00
										 |  |  | 	int type = ttm_bo_type_device; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (sg) | 
					
						
							|  |  |  | 		type = ttm_bo_type_sg; | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	nvbo = kzalloc(sizeof(struct nouveau_bo), GFP_KERNEL); | 
					
						
							|  |  |  | 	if (!nvbo) | 
					
						
							|  |  |  | 		return -ENOMEM; | 
					
						
							|  |  |  | 	INIT_LIST_HEAD(&nvbo->head); | 
					
						
							|  |  |  | 	INIT_LIST_HEAD(&nvbo->entry); | 
					
						
							| 
									
										
										
										
											2011-06-06 14:07:04 +10:00
										 |  |  | 	INIT_LIST_HEAD(&nvbo->vma_list); | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 	nvbo->tile_mode = tile_mode; | 
					
						
							|  |  |  | 	nvbo->tile_flags = tile_flags; | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	nvbo->bo.bdev = &drm->ttm.bdev; | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-06 14:15:46 +10:00
										 |  |  | 	nvbo->page_shift = 12; | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	if (drm->client.base.vm) { | 
					
						
							| 
									
										
										
										
											2011-06-06 14:15:46 +10:00
										 |  |  | 		if (!(flags & TTM_PL_FLAG_TT) && size > 256 * 1024) | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 			nvbo->page_shift = drm->client.base.vm->vmm->lpg_shift; | 
					
						
							| 
									
										
										
										
											2011-06-06 14:15:46 +10:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	nouveau_bo_fixup_align(nvbo, flags, &align, &size); | 
					
						
							| 
									
										
										
										
											2011-06-06 14:07:04 +10:00
										 |  |  | 	nvbo->bo.mem.num_pages = size >> PAGE_SHIFT; | 
					
						
							|  |  |  | 	nouveau_bo_placement_set(nvbo, flags, 0); | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	acc_size = ttm_bo_dma_acc_size(&drm->ttm.bdev, size, | 
					
						
							| 
									
										
										
										
											2011-11-11 15:42:57 -05:00
										 |  |  | 				       sizeof(struct nouveau_bo)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	ret = ttm_bo_init(&drm->ttm.bdev, &nvbo->bo, size, | 
					
						
							| 
									
										
										
										
											2012-04-02 11:53:06 +01:00
										 |  |  | 			  type, &nvbo->placement, | 
					
						
							| 
									
										
										
										
											2012-11-06 21:49:51 +00:00
										 |  |  | 			  align >> PAGE_SHIFT, false, NULL, acc_size, sg, | 
					
						
							| 
									
										
										
										
											2011-06-06 14:07:04 +10:00
										 |  |  | 			  nouveau_bo_del_ttm); | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 	if (ret) { | 
					
						
							|  |  |  | 		/* ttm will call nouveau_bo_del_ttm if it fails.. */ | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	*pnvbo = nvbo; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-18 13:07:47 +01:00
										 |  |  | static void | 
					
						
							|  |  |  | set_placement_list(uint32_t *pl, unsigned *n, uint32_t type, uint32_t flags) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	*n = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (type & TTM_PL_FLAG_VRAM) | 
					
						
							|  |  |  | 		pl[(*n)++] = TTM_PL_FLAG_VRAM | flags; | 
					
						
							|  |  |  | 	if (type & TTM_PL_FLAG_TT) | 
					
						
							|  |  |  | 		pl[(*n)++] = TTM_PL_FLAG_TT | flags; | 
					
						
							|  |  |  | 	if (type & TTM_PL_FLAG_SYSTEM) | 
					
						
							|  |  |  | 		pl[(*n)++] = TTM_PL_FLAG_SYSTEM | flags; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-10-10 06:07:32 +02:00
										 |  |  | static void | 
					
						
							|  |  |  | set_placement_range(struct nouveau_bo *nvbo, uint32_t type) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev); | 
					
						
							|  |  |  | 	struct nouveau_fb *pfb = nouveau_fb(drm->device); | 
					
						
							|  |  |  | 	u32 vram_pages = pfb->ram.size >> PAGE_SHIFT; | 
					
						
							| 
									
										
										
										
											2010-10-10 06:07:32 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	if (nv_device(drm->device)->card_type == NV_10 && | 
					
						
							| 
									
										
										
										
											2011-02-03 01:49:33 +01:00
										 |  |  | 	    nvbo->tile_mode && (type & TTM_PL_FLAG_VRAM) && | 
					
						
							| 
									
										
										
										
											2011-11-06 21:21:28 +01:00
										 |  |  | 	    nvbo->bo.mem.num_pages < vram_pages / 4) { | 
					
						
							| 
									
										
										
										
											2010-10-10 06:07:32 +02:00
										 |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * Make sure that the color and depth buffers are handled | 
					
						
							|  |  |  | 		 * by independent memory controller units. Up to a 9x | 
					
						
							|  |  |  | 		 * speed up when alpha-blending and depth-test are enabled | 
					
						
							|  |  |  | 		 * at the same time. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		if (nvbo->tile_flags & NOUVEAU_GEM_TILE_ZETA) { | 
					
						
							|  |  |  | 			nvbo->placement.fpfn = vram_pages / 2; | 
					
						
							|  |  |  | 			nvbo->placement.lpfn = ~0; | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			nvbo->placement.fpfn = 0; | 
					
						
							|  |  |  | 			nvbo->placement.lpfn = vram_pages / 2; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | void | 
					
						
							| 
									
										
										
										
											2010-03-18 13:07:47 +01:00
										 |  |  | nouveau_bo_placement_set(struct nouveau_bo *nvbo, uint32_t type, uint32_t busy) | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-03-18 13:07:47 +01:00
										 |  |  | 	struct ttm_placement *pl = &nvbo->placement; | 
					
						
							|  |  |  | 	uint32_t flags = TTM_PL_MASK_CACHING | | 
					
						
							|  |  |  | 		(nvbo->pin_refcnt ? TTM_PL_FLAG_NO_EVICT : 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pl->placement = nvbo->placements; | 
					
						
							|  |  |  | 	set_placement_list(nvbo->placements, &pl->num_placement, | 
					
						
							|  |  |  | 			   type, flags); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pl->busy_placement = nvbo->busy_placements; | 
					
						
							|  |  |  | 	set_placement_list(nvbo->busy_placements, &pl->num_busy_placement, | 
					
						
							|  |  |  | 			   type | busy, flags); | 
					
						
							| 
									
										
										
										
											2010-10-10 06:07:32 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	set_placement_range(nvbo, type); | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t memtype) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev); | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 	struct ttm_buffer_object *bo = &nvbo->bo; | 
					
						
							| 
									
										
										
										
											2010-03-18 13:07:47 +01:00
										 |  |  | 	int ret; | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-11 21:52:30 +01:00
										 |  |  | 	ret = ttm_bo_reserve(bo, false, false, false, 0); | 
					
						
							|  |  |  | 	if (ret) | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 	if (nvbo->pin_refcnt && !(memtype & (1 << bo->mem.mem_type))) { | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 		NV_ERROR(drm, "bo %p pinned elsewhere: 0x%08x vs 0x%08x\n", bo, | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 			 1 << bo->mem.mem_type, memtype); | 
					
						
							| 
									
										
										
										
											2012-12-11 21:52:30 +01:00
										 |  |  | 		ret = -EINVAL; | 
					
						
							|  |  |  | 		goto out; | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (nvbo->pin_refcnt++) | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-18 13:07:47 +01:00
										 |  |  | 	nouveau_bo_placement_set(nvbo, memtype, 0); | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-28 11:25:44 +00:00
										 |  |  | 	ret = nouveau_bo_validate(nvbo, false, false); | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 	if (ret == 0) { | 
					
						
							|  |  |  | 		switch (bo->mem.mem_type) { | 
					
						
							|  |  |  | 		case TTM_PL_VRAM: | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 			drm->gem.vram_available -= bo->mem.size; | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		case TTM_PL_TT: | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 			drm->gem.gart_available -= bo->mem.size; | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | out: | 
					
						
							| 
									
										
										
										
											2012-12-11 21:52:30 +01:00
										 |  |  | 	ttm_bo_unreserve(bo); | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | nouveau_bo_unpin(struct nouveau_bo *nvbo) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev); | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 	struct ttm_buffer_object *bo = &nvbo->bo; | 
					
						
							| 
									
										
										
										
											2010-03-18 13:07:47 +01:00
										 |  |  | 	int ret; | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	ret = ttm_bo_reserve(bo, false, false, false, 0); | 
					
						
							|  |  |  | 	if (ret) | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-11 21:52:30 +01:00
										 |  |  | 	if (--nvbo->pin_refcnt) | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-18 13:07:47 +01:00
										 |  |  | 	nouveau_bo_placement_set(nvbo, bo->mem.placement, 0); | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-28 11:25:44 +00:00
										 |  |  | 	ret = nouveau_bo_validate(nvbo, false, false); | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 	if (ret == 0) { | 
					
						
							|  |  |  | 		switch (bo->mem.mem_type) { | 
					
						
							|  |  |  | 		case TTM_PL_VRAM: | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 			drm->gem.vram_available += bo->mem.size; | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		case TTM_PL_TT: | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 			drm->gem.gart_available += bo->mem.size; | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-11 21:52:30 +01:00
										 |  |  | out: | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 	ttm_bo_unreserve(bo); | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | nouveau_bo_map(struct nouveau_bo *nvbo) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = ttm_bo_reserve(&nvbo->bo, false, false, false, 0); | 
					
						
							|  |  |  | 	if (ret) | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = ttm_bo_kmap(&nvbo->bo, 0, nvbo->bo.mem.num_pages, &nvbo->kmap); | 
					
						
							|  |  |  | 	ttm_bo_unreserve(&nvbo->bo); | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | nouveau_bo_unmap(struct nouveau_bo *nvbo) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-08-27 13:04:41 +10:00
										 |  |  | 	if (nvbo) | 
					
						
							|  |  |  | 		ttm_bo_kunmap(&nvbo->kmap); | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-22 08:50:27 +10:00
										 |  |  | int | 
					
						
							|  |  |  | nouveau_bo_validate(struct nouveau_bo *nvbo, bool interruptible, | 
					
						
							| 
									
										
										
										
											2012-11-28 11:25:44 +00:00
										 |  |  | 		    bool no_wait_gpu) | 
					
						
							| 
									
										
										
										
											2010-11-22 08:50:27 +10:00
										 |  |  | { | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-28 11:25:44 +00:00
										 |  |  | 	ret = ttm_bo_validate(&nvbo->bo, &nvbo->placement, | 
					
						
							|  |  |  | 			      interruptible, no_wait_gpu); | 
					
						
							| 
									
										
										
										
											2010-11-22 08:50:27 +10:00
										 |  |  | 	if (ret) | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | u16 | 
					
						
							|  |  |  | nouveau_bo_rd16(struct nouveau_bo *nvbo, unsigned index) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	bool is_iomem; | 
					
						
							|  |  |  | 	u16 *mem = ttm_kmap_obj_virtual(&nvbo->kmap, &is_iomem); | 
					
						
							|  |  |  | 	mem = &mem[index]; | 
					
						
							|  |  |  | 	if (is_iomem) | 
					
						
							|  |  |  | 		return ioread16_native((void __force __iomem *)mem); | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		return *mem; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | nouveau_bo_wr16(struct nouveau_bo *nvbo, unsigned index, u16 val) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	bool is_iomem; | 
					
						
							|  |  |  | 	u16 *mem = ttm_kmap_obj_virtual(&nvbo->kmap, &is_iomem); | 
					
						
							|  |  |  | 	mem = &mem[index]; | 
					
						
							|  |  |  | 	if (is_iomem) | 
					
						
							|  |  |  | 		iowrite16_native(val, (void __force __iomem *)mem); | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		*mem = val; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | u32 | 
					
						
							|  |  |  | nouveau_bo_rd32(struct nouveau_bo *nvbo, unsigned index) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	bool is_iomem; | 
					
						
							|  |  |  | 	u32 *mem = ttm_kmap_obj_virtual(&nvbo->kmap, &is_iomem); | 
					
						
							|  |  |  | 	mem = &mem[index]; | 
					
						
							|  |  |  | 	if (is_iomem) | 
					
						
							|  |  |  | 		return ioread32_native((void __force __iomem *)mem); | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		return *mem; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | nouveau_bo_wr32(struct nouveau_bo *nvbo, unsigned index, u32 val) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	bool is_iomem; | 
					
						
							|  |  |  | 	u32 *mem = ttm_kmap_obj_virtual(&nvbo->kmap, &is_iomem); | 
					
						
							|  |  |  | 	mem = &mem[index]; | 
					
						
							|  |  |  | 	if (is_iomem) | 
					
						
							|  |  |  | 		iowrite32_native(val, (void __force __iomem *)mem); | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		*mem = val; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-01 20:46:13 -04:00
										 |  |  | static struct ttm_tt * | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | nouveau_ttm_tt_create(struct ttm_bo_device *bdev, unsigned long size, | 
					
						
							|  |  |  | 		      uint32_t page_flags, struct page *dummy_read) | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-10-14 01:58:26 +04:00
										 |  |  | #if __OS_HAS_AGP
 | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	struct nouveau_drm *drm = nouveau_bdev(bdev); | 
					
						
							|  |  |  | 	struct drm_device *dev = drm->dev; | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	if (drm->agp.stat == ENABLED) { | 
					
						
							|  |  |  | 		return ttm_agp_tt_create(bdev, dev->agp->bridge, size, | 
					
						
							|  |  |  | 					 page_flags, dummy_read); | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-10-14 01:58:26 +04:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	return nouveau_sgdma_create_ttm(bdev, size, page_flags, dummy_read); | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | nouveau_bo_invalidate_caches(struct ttm_bo_device *bdev, uint32_t flags) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/* We'll do this from user space. */ | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | nouveau_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, | 
					
						
							|  |  |  | 			 struct ttm_mem_type_manager *man) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	struct nouveau_drm *drm = nouveau_bdev(bdev); | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	switch (type) { | 
					
						
							|  |  |  | 	case TTM_PL_SYSTEM: | 
					
						
							|  |  |  | 		man->flags = TTM_MEMTYPE_FLAG_MAPPABLE; | 
					
						
							|  |  |  | 		man->available_caching = TTM_PL_MASK_CACHING; | 
					
						
							|  |  |  | 		man->default_caching = TTM_PL_FLAG_CACHED; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case TTM_PL_VRAM: | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 		if (nv_device(drm->device)->card_type >= NV_50) { | 
					
						
							| 
									
										
										
										
											2010-08-25 15:26:04 +10:00
										 |  |  | 			man->func = &nouveau_vram_manager; | 
					
						
							| 
									
										
										
										
											2010-11-15 11:53:16 +10:00
										 |  |  | 			man->io_reserve_fastpath = false; | 
					
						
							|  |  |  | 			man->use_io_reserve_lru = true; | 
					
						
							|  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2010-08-25 15:26:04 +10:00
										 |  |  | 			man->func = &ttm_bo_manager_func; | 
					
						
							| 
									
										
										
										
											2010-11-15 11:53:16 +10:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 		man->flags = TTM_MEMTYPE_FLAG_FIXED | | 
					
						
							| 
									
										
										
										
											2010-04-09 14:39:25 +02:00
										 |  |  | 			     TTM_MEMTYPE_FLAG_MAPPABLE; | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 		man->available_caching = TTM_PL_FLAG_UNCACHED | | 
					
						
							|  |  |  | 					 TTM_PL_FLAG_WC; | 
					
						
							|  |  |  | 		man->default_caching = TTM_PL_FLAG_WC; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case TTM_PL_TT: | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 		if (nv_device(drm->device)->card_type >= NV_50) | 
					
						
							| 
									
										
										
										
											2011-02-10 12:59:51 +10:00
										 |  |  | 			man->func = &nouveau_gart_manager; | 
					
						
							| 
									
										
										
										
											2012-07-14 19:09:17 +10:00
										 |  |  | 		else | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 		if (drm->agp.stat != ENABLED) | 
					
						
							| 
									
										
										
										
											2012-07-14 19:09:17 +10:00
										 |  |  | 			man->func = &nv04_gart_manager; | 
					
						
							| 
									
										
										
										
											2011-02-10 12:59:51 +10:00
										 |  |  | 		else | 
					
						
							|  |  |  | 			man->func = &ttm_bo_manager_func; | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (drm->agp.stat == ENABLED) { | 
					
						
							| 
									
										
										
										
											2010-04-09 14:39:25 +02:00
										 |  |  | 			man->flags = TTM_MEMTYPE_FLAG_MAPPABLE; | 
					
						
							| 
									
										
										
										
											2010-11-20 22:11:22 +01:00
										 |  |  | 			man->available_caching = TTM_PL_FLAG_UNCACHED | | 
					
						
							|  |  |  | 				TTM_PL_FLAG_WC; | 
					
						
							|  |  |  | 			man->default_caching = TTM_PL_FLAG_WC; | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 			man->flags = TTM_MEMTYPE_FLAG_MAPPABLE | | 
					
						
							|  |  |  | 				     TTM_MEMTYPE_FLAG_CMA; | 
					
						
							|  |  |  | 			man->available_caching = TTM_PL_MASK_CACHING; | 
					
						
							|  |  |  | 			man->default_caching = TTM_PL_FLAG_CACHED; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | nouveau_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct nouveau_bo *nvbo = nouveau_bo(bo); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (bo->mem.mem_type) { | 
					
						
							| 
									
										
										
										
											2009-12-11 18:40:17 +01:00
										 |  |  | 	case TTM_PL_VRAM: | 
					
						
							| 
									
										
										
										
											2010-03-18 13:07:47 +01:00
										 |  |  | 		nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_TT, | 
					
						
							|  |  |  | 					 TTM_PL_FLAG_SYSTEM); | 
					
						
							| 
									
										
										
										
											2009-12-11 18:40:17 +01:00
										 |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2010-03-18 13:07:47 +01:00
										 |  |  | 		nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_SYSTEM, 0); | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-12-11 18:40:17 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	*pl = nvbo->placement; | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* GPU-assisted copy using NV_MEMORY_TO_MEMORY_FORMAT, can access
 | 
					
						
							|  |  |  |  * TTM_PL_{VRAM,TT} directly. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2009-12-11 16:51:09 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | static int | 
					
						
							|  |  |  | nouveau_bo_move_accel_cleanup(struct nouveau_channel *chan, | 
					
						
							| 
									
										
										
										
											2010-04-07 10:21:19 +00:00
										 |  |  | 			      struct nouveau_bo *nvbo, bool evict, | 
					
						
							| 
									
										
										
										
											2012-11-28 11:25:44 +00:00
										 |  |  | 			      bool no_wait_gpu, struct ttm_mem_reg *new_mem) | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct nouveau_fence *fence = NULL; | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-14 13:43:21 +10:00
										 |  |  | 	ret = nouveau_fence_new(chan, false, &fence); | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 	if (ret) | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-12 15:03:11 +00:00
										 |  |  | 	ret = ttm_bo_move_accel_cleanup(&nvbo->bo, fence, evict, | 
					
						
							| 
									
										
										
										
											2012-11-28 11:25:44 +00:00
										 |  |  | 					no_wait_gpu, new_mem); | 
					
						
							| 
									
										
										
										
											2010-10-20 21:50:24 +02:00
										 |  |  | 	nouveau_fence_unref(&fence); | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-06 19:38:25 +10:00
										 |  |  | static int | 
					
						
							|  |  |  | nve0_bo_move_init(struct nouveau_channel *chan, u32 handle) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int ret = RING_SPACE(chan, 2); | 
					
						
							|  |  |  | 	if (ret == 0) { | 
					
						
							|  |  |  | 		BEGIN_NVC0(chan, NvSubCopy, 0x0000, 1); | 
					
						
							|  |  |  | 		OUT_RING  (chan, handle); | 
					
						
							|  |  |  | 		FIRE_RING (chan); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-20 14:36:04 +10:00
										 |  |  | static int | 
					
						
							|  |  |  | nve0_bo_move_copy(struct nouveau_channel *chan, struct ttm_buffer_object *bo, | 
					
						
							|  |  |  | 		  struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct nouveau_mem *node = old_mem->mm_node; | 
					
						
							|  |  |  | 	int ret = RING_SPACE(chan, 10); | 
					
						
							|  |  |  | 	if (ret == 0) { | 
					
						
							| 
									
										
										
										
											2012-04-01 21:09:13 +10:00
										 |  |  | 		BEGIN_NVC0(chan, NvSubCopy, 0x0400, 8); | 
					
						
							| 
									
										
										
										
											2012-03-20 14:36:04 +10:00
										 |  |  | 		OUT_RING  (chan, upper_32_bits(node->vma[0].offset)); | 
					
						
							|  |  |  | 		OUT_RING  (chan, lower_32_bits(node->vma[0].offset)); | 
					
						
							|  |  |  | 		OUT_RING  (chan, upper_32_bits(node->vma[1].offset)); | 
					
						
							|  |  |  | 		OUT_RING  (chan, lower_32_bits(node->vma[1].offset)); | 
					
						
							|  |  |  | 		OUT_RING  (chan, PAGE_SIZE); | 
					
						
							|  |  |  | 		OUT_RING  (chan, PAGE_SIZE); | 
					
						
							|  |  |  | 		OUT_RING  (chan, PAGE_SIZE); | 
					
						
							|  |  |  | 		OUT_RING  (chan, new_mem->num_pages); | 
					
						
							| 
									
										
										
										
											2012-04-01 21:09:13 +10:00
										 |  |  | 		BEGIN_IMC0(chan, NvSubCopy, 0x0300, 0x0386); | 
					
						
							| 
									
										
										
										
											2012-03-20 14:36:04 +10:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-04 14:01:52 +10:00
										 |  |  | static int | 
					
						
							|  |  |  | nvc0_bo_move_init(struct nouveau_channel *chan, u32 handle) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int ret = RING_SPACE(chan, 2); | 
					
						
							|  |  |  | 	if (ret == 0) { | 
					
						
							|  |  |  | 		BEGIN_NVC0(chan, NvSubCopy, 0x0000, 1); | 
					
						
							|  |  |  | 		OUT_RING  (chan, handle); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-04 15:17:28 +10:00
										 |  |  | static int | 
					
						
							|  |  |  | nvc0_bo_move_copy(struct nouveau_channel *chan, struct ttm_buffer_object *bo, | 
					
						
							|  |  |  | 		  struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct nouveau_mem *node = old_mem->mm_node; | 
					
						
							|  |  |  | 	u64 src_offset = node->vma[0].offset; | 
					
						
							|  |  |  | 	u64 dst_offset = node->vma[1].offset; | 
					
						
							|  |  |  | 	u32 page_count = new_mem->num_pages; | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	page_count = new_mem->num_pages; | 
					
						
							|  |  |  | 	while (page_count) { | 
					
						
							|  |  |  | 		int line_count = (page_count > 8191) ? 8191 : page_count; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ret = RING_SPACE(chan, 11); | 
					
						
							|  |  |  | 		if (ret) | 
					
						
							|  |  |  | 			return ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		BEGIN_NVC0(chan, NvSubCopy, 0x030c, 8); | 
					
						
							|  |  |  | 		OUT_RING  (chan, upper_32_bits(src_offset)); | 
					
						
							|  |  |  | 		OUT_RING  (chan, lower_32_bits(src_offset)); | 
					
						
							|  |  |  | 		OUT_RING  (chan, upper_32_bits(dst_offset)); | 
					
						
							|  |  |  | 		OUT_RING  (chan, lower_32_bits(dst_offset)); | 
					
						
							|  |  |  | 		OUT_RING  (chan, PAGE_SIZE); | 
					
						
							|  |  |  | 		OUT_RING  (chan, PAGE_SIZE); | 
					
						
							|  |  |  | 		OUT_RING  (chan, PAGE_SIZE); | 
					
						
							|  |  |  | 		OUT_RING  (chan, line_count); | 
					
						
							|  |  |  | 		BEGIN_NVC0(chan, NvSubCopy, 0x0300, 1); | 
					
						
							|  |  |  | 		OUT_RING  (chan, 0x00000110); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		page_count -= line_count; | 
					
						
							|  |  |  | 		src_offset += (PAGE_SIZE * line_count); | 
					
						
							|  |  |  | 		dst_offset += (PAGE_SIZE * line_count); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-12-09 15:17:10 +10:00
										 |  |  | static int | 
					
						
							|  |  |  | nvc0_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, | 
					
						
							|  |  |  | 		  struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-06-06 20:54:42 +10:00
										 |  |  | 	struct nouveau_mem *node = old_mem->mm_node; | 
					
						
							|  |  |  | 	u64 src_offset = node->vma[0].offset; | 
					
						
							|  |  |  | 	u64 dst_offset = node->vma[1].offset; | 
					
						
							| 
									
										
										
										
											2010-12-09 15:17:10 +10:00
										 |  |  | 	u32 page_count = new_mem->num_pages; | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	page_count = new_mem->num_pages; | 
					
						
							|  |  |  | 	while (page_count) { | 
					
						
							|  |  |  | 		int line_count = (page_count > 2047) ? 2047 : page_count; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ret = RING_SPACE(chan, 12); | 
					
						
							|  |  |  | 		if (ret) | 
					
						
							|  |  |  | 			return ret; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-04 14:01:52 +10:00
										 |  |  | 		BEGIN_NVC0(chan, NvSubCopy, 0x0238, 2); | 
					
						
							| 
									
										
										
										
											2010-12-09 15:17:10 +10:00
										 |  |  | 		OUT_RING  (chan, upper_32_bits(dst_offset)); | 
					
						
							|  |  |  | 		OUT_RING  (chan, lower_32_bits(dst_offset)); | 
					
						
							| 
									
										
										
										
											2012-05-04 14:01:52 +10:00
										 |  |  | 		BEGIN_NVC0(chan, NvSubCopy, 0x030c, 6); | 
					
						
							| 
									
										
										
										
											2010-12-09 15:17:10 +10:00
										 |  |  | 		OUT_RING  (chan, upper_32_bits(src_offset)); | 
					
						
							|  |  |  | 		OUT_RING  (chan, lower_32_bits(src_offset)); | 
					
						
							|  |  |  | 		OUT_RING  (chan, PAGE_SIZE); /* src_pitch */ | 
					
						
							|  |  |  | 		OUT_RING  (chan, PAGE_SIZE); /* dst_pitch */ | 
					
						
							|  |  |  | 		OUT_RING  (chan, PAGE_SIZE); /* line_length */ | 
					
						
							|  |  |  | 		OUT_RING  (chan, line_count); | 
					
						
							| 
									
										
										
										
											2012-05-04 14:01:52 +10:00
										 |  |  | 		BEGIN_NVC0(chan, NvSubCopy, 0x0300, 1); | 
					
						
							| 
									
										
										
										
											2010-12-09 15:17:10 +10:00
										 |  |  | 		OUT_RING  (chan, 0x00100110); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		page_count -= line_count; | 
					
						
							|  |  |  | 		src_offset += (PAGE_SIZE * line_count); | 
					
						
							|  |  |  | 		dst_offset += (PAGE_SIZE * line_count); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-04 15:15:12 +10:00
										 |  |  | static int | 
					
						
							|  |  |  | nva3_bo_move_copy(struct nouveau_channel *chan, struct ttm_buffer_object *bo, | 
					
						
							|  |  |  | 		  struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct nouveau_mem *node = old_mem->mm_node; | 
					
						
							|  |  |  | 	u64 src_offset = node->vma[0].offset; | 
					
						
							|  |  |  | 	u64 dst_offset = node->vma[1].offset; | 
					
						
							|  |  |  | 	u32 page_count = new_mem->num_pages; | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	page_count = new_mem->num_pages; | 
					
						
							|  |  |  | 	while (page_count) { | 
					
						
							|  |  |  | 		int line_count = (page_count > 8191) ? 8191 : page_count; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ret = RING_SPACE(chan, 11); | 
					
						
							|  |  |  | 		if (ret) | 
					
						
							|  |  |  | 			return ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		BEGIN_NV04(chan, NvSubCopy, 0x030c, 8); | 
					
						
							|  |  |  | 		OUT_RING  (chan, upper_32_bits(src_offset)); | 
					
						
							|  |  |  | 		OUT_RING  (chan, lower_32_bits(src_offset)); | 
					
						
							|  |  |  | 		OUT_RING  (chan, upper_32_bits(dst_offset)); | 
					
						
							|  |  |  | 		OUT_RING  (chan, lower_32_bits(dst_offset)); | 
					
						
							|  |  |  | 		OUT_RING  (chan, PAGE_SIZE); | 
					
						
							|  |  |  | 		OUT_RING  (chan, PAGE_SIZE); | 
					
						
							|  |  |  | 		OUT_RING  (chan, PAGE_SIZE); | 
					
						
							|  |  |  | 		OUT_RING  (chan, line_count); | 
					
						
							|  |  |  | 		BEGIN_NV04(chan, NvSubCopy, 0x0300, 1); | 
					
						
							|  |  |  | 		OUT_RING  (chan, 0x00000110); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		page_count -= line_count; | 
					
						
							|  |  |  | 		src_offset += (PAGE_SIZE * line_count); | 
					
						
							|  |  |  | 		dst_offset += (PAGE_SIZE * line_count); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-04 14:34:16 +10:00
										 |  |  | static int | 
					
						
							|  |  |  | nv98_bo_move_exec(struct nouveau_channel *chan, struct ttm_buffer_object *bo, | 
					
						
							|  |  |  | 		  struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct nouveau_mem *node = old_mem->mm_node; | 
					
						
							|  |  |  | 	int ret = RING_SPACE(chan, 7); | 
					
						
							|  |  |  | 	if (ret == 0) { | 
					
						
							|  |  |  | 		BEGIN_NV04(chan, NvSubCopy, 0x0320, 6); | 
					
						
							|  |  |  | 		OUT_RING  (chan, upper_32_bits(node->vma[0].offset)); | 
					
						
							|  |  |  | 		OUT_RING  (chan, lower_32_bits(node->vma[0].offset)); | 
					
						
							|  |  |  | 		OUT_RING  (chan, upper_32_bits(node->vma[1].offset)); | 
					
						
							|  |  |  | 		OUT_RING  (chan, lower_32_bits(node->vma[1].offset)); | 
					
						
							|  |  |  | 		OUT_RING  (chan, 0x00000000 /* COPY */); | 
					
						
							|  |  |  | 		OUT_RING  (chan, new_mem->num_pages << PAGE_SHIFT); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-04 14:21:15 +10:00
										 |  |  | static int | 
					
						
							|  |  |  | nv84_bo_move_exec(struct nouveau_channel *chan, struct ttm_buffer_object *bo, | 
					
						
							|  |  |  | 		  struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct nouveau_mem *node = old_mem->mm_node; | 
					
						
							|  |  |  | 	int ret = RING_SPACE(chan, 7); | 
					
						
							|  |  |  | 	if (ret == 0) { | 
					
						
							|  |  |  | 		BEGIN_NV04(chan, NvSubCopy, 0x0304, 6); | 
					
						
							|  |  |  | 		OUT_RING  (chan, new_mem->num_pages << PAGE_SHIFT); | 
					
						
							|  |  |  | 		OUT_RING  (chan, upper_32_bits(node->vma[0].offset)); | 
					
						
							|  |  |  | 		OUT_RING  (chan, lower_32_bits(node->vma[0].offset)); | 
					
						
							|  |  |  | 		OUT_RING  (chan, upper_32_bits(node->vma[1].offset)); | 
					
						
							|  |  |  | 		OUT_RING  (chan, lower_32_bits(node->vma[1].offset)); | 
					
						
							|  |  |  | 		OUT_RING  (chan, 0x00000000 /* MODE_COPY, QUERY_NONE */); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-04 14:01:52 +10:00
										 |  |  | static int | 
					
						
							|  |  |  | nv50_bo_move_init(struct nouveau_channel *chan, u32 handle) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	int ret = RING_SPACE(chan, 6); | 
					
						
							| 
									
										
										
										
											2012-05-04 14:01:52 +10:00
										 |  |  | 	if (ret == 0) { | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 		BEGIN_NV04(chan, NvSubCopy, 0x0000, 1); | 
					
						
							|  |  |  | 		OUT_RING  (chan, handle); | 
					
						
							|  |  |  | 		BEGIN_NV04(chan, NvSubCopy, 0x0180, 3); | 
					
						
							|  |  |  | 		OUT_RING  (chan, NvNotify0); | 
					
						
							|  |  |  | 		OUT_RING  (chan, NvDmaFB); | 
					
						
							|  |  |  | 		OUT_RING  (chan, NvDmaFB); | 
					
						
							| 
									
										
										
										
											2012-05-04 14:01:52 +10:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | static int | 
					
						
							| 
									
										
										
										
											2010-08-26 11:32:01 +10:00
										 |  |  | nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, | 
					
						
							|  |  |  | 		  struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem) | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-06-06 20:54:42 +10:00
										 |  |  | 	struct nouveau_mem *node = old_mem->mm_node; | 
					
						
							| 
									
										
										
										
											2010-08-26 11:32:01 +10:00
										 |  |  | 	struct nouveau_bo *nvbo = nouveau_bo(bo); | 
					
						
							|  |  |  | 	u64 length = (new_mem->num_pages << PAGE_SHIFT); | 
					
						
							| 
									
										
										
										
											2011-06-06 20:54:42 +10:00
										 |  |  | 	u64 src_offset = node->vma[0].offset; | 
					
						
							|  |  |  | 	u64 dst_offset = node->vma[1].offset; | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-26 11:32:01 +10:00
										 |  |  | 	while (length) { | 
					
						
							|  |  |  | 		u32 amount, stride, height; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-09-23 15:21:17 +10:00
										 |  |  | 		amount  = min(length, (u64)(4 * 1024 * 1024)); | 
					
						
							|  |  |  | 		stride  = 16 * 4; | 
					
						
							| 
									
										
										
										
											2010-08-26 11:32:01 +10:00
										 |  |  | 		height  = amount / stride; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-03 13:32:00 +01:00
										 |  |  | 		if (old_mem->mem_type == TTM_PL_VRAM && | 
					
						
							| 
									
										
										
										
											2010-10-10 06:01:08 +02:00
										 |  |  | 		    nouveau_bo_tile_layout(nvbo)) { | 
					
						
							| 
									
										
										
										
											2010-08-26 11:32:01 +10:00
										 |  |  | 			ret = RING_SPACE(chan, 8); | 
					
						
							|  |  |  | 			if (ret) | 
					
						
							|  |  |  | 				return ret; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-04 14:01:52 +10:00
										 |  |  | 			BEGIN_NV04(chan, NvSubCopy, 0x0200, 7); | 
					
						
							| 
									
										
										
										
											2010-08-26 11:32:01 +10:00
										 |  |  | 			OUT_RING  (chan, 0); | 
					
						
							| 
									
										
										
										
											2010-09-23 15:21:17 +10:00
										 |  |  | 			OUT_RING  (chan, 0); | 
					
						
							| 
									
										
										
										
											2010-08-26 11:32:01 +10:00
										 |  |  | 			OUT_RING  (chan, stride); | 
					
						
							|  |  |  | 			OUT_RING  (chan, height); | 
					
						
							|  |  |  | 			OUT_RING  (chan, 1); | 
					
						
							|  |  |  | 			OUT_RING  (chan, 0); | 
					
						
							|  |  |  | 			OUT_RING  (chan, 0); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			ret = RING_SPACE(chan, 2); | 
					
						
							|  |  |  | 			if (ret) | 
					
						
							|  |  |  | 				return ret; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-04 14:01:52 +10:00
										 |  |  | 			BEGIN_NV04(chan, NvSubCopy, 0x0200, 1); | 
					
						
							| 
									
										
										
										
											2010-08-26 11:32:01 +10:00
										 |  |  | 			OUT_RING  (chan, 1); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2013-03-03 13:32:00 +01:00
										 |  |  | 		if (new_mem->mem_type == TTM_PL_VRAM && | 
					
						
							| 
									
										
										
										
											2010-10-10 06:01:08 +02:00
										 |  |  | 		    nouveau_bo_tile_layout(nvbo)) { | 
					
						
							| 
									
										
										
										
											2010-08-26 11:32:01 +10:00
										 |  |  | 			ret = RING_SPACE(chan, 8); | 
					
						
							|  |  |  | 			if (ret) | 
					
						
							|  |  |  | 				return ret; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-04 14:01:52 +10:00
										 |  |  | 			BEGIN_NV04(chan, NvSubCopy, 0x021c, 7); | 
					
						
							| 
									
										
										
										
											2010-08-26 11:32:01 +10:00
										 |  |  | 			OUT_RING  (chan, 0); | 
					
						
							| 
									
										
										
										
											2010-09-23 15:21:17 +10:00
										 |  |  | 			OUT_RING  (chan, 0); | 
					
						
							| 
									
										
										
										
											2010-08-26 11:32:01 +10:00
										 |  |  | 			OUT_RING  (chan, stride); | 
					
						
							|  |  |  | 			OUT_RING  (chan, height); | 
					
						
							|  |  |  | 			OUT_RING  (chan, 1); | 
					
						
							|  |  |  | 			OUT_RING  (chan, 0); | 
					
						
							|  |  |  | 			OUT_RING  (chan, 0); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			ret = RING_SPACE(chan, 2); | 
					
						
							|  |  |  | 			if (ret) | 
					
						
							|  |  |  | 				return ret; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-04 14:01:52 +10:00
										 |  |  | 			BEGIN_NV04(chan, NvSubCopy, 0x021c, 1); | 
					
						
							| 
									
										
										
										
											2010-08-26 11:32:01 +10:00
										 |  |  | 			OUT_RING  (chan, 1); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ret = RING_SPACE(chan, 14); | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 		if (ret) | 
					
						
							|  |  |  | 			return ret; | 
					
						
							| 
									
										
										
										
											2010-08-26 11:32:01 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-04 14:01:52 +10:00
										 |  |  | 		BEGIN_NV04(chan, NvSubCopy, 0x0238, 2); | 
					
						
							| 
									
										
										
										
											2010-08-26 11:32:01 +10:00
										 |  |  | 		OUT_RING  (chan, upper_32_bits(src_offset)); | 
					
						
							|  |  |  | 		OUT_RING  (chan, upper_32_bits(dst_offset)); | 
					
						
							| 
									
										
										
										
											2012-05-04 14:01:52 +10:00
										 |  |  | 		BEGIN_NV04(chan, NvSubCopy, 0x030c, 8); | 
					
						
							| 
									
										
										
										
											2010-08-26 11:32:01 +10:00
										 |  |  | 		OUT_RING  (chan, lower_32_bits(src_offset)); | 
					
						
							|  |  |  | 		OUT_RING  (chan, lower_32_bits(dst_offset)); | 
					
						
							|  |  |  | 		OUT_RING  (chan, stride); | 
					
						
							|  |  |  | 		OUT_RING  (chan, stride); | 
					
						
							|  |  |  | 		OUT_RING  (chan, stride); | 
					
						
							|  |  |  | 		OUT_RING  (chan, height); | 
					
						
							|  |  |  | 		OUT_RING  (chan, 0x00000101); | 
					
						
							|  |  |  | 		OUT_RING  (chan, 0x00000000); | 
					
						
							| 
									
										
										
										
											2012-05-04 14:01:52 +10:00
										 |  |  | 		BEGIN_NV04(chan, NvSubCopy, NV_MEMORY_TO_MEMORY_FORMAT_NOP, 1); | 
					
						
							| 
									
										
										
										
											2010-08-26 11:32:01 +10:00
										 |  |  | 		OUT_RING  (chan, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		length -= amount; | 
					
						
							|  |  |  | 		src_offset += amount; | 
					
						
							|  |  |  | 		dst_offset += amount; | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-26 11:32:01 +10:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-04 14:01:52 +10:00
										 |  |  | static int | 
					
						
							|  |  |  | nv04_bo_move_init(struct nouveau_channel *chan, u32 handle) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	int ret = RING_SPACE(chan, 4); | 
					
						
							| 
									
										
										
										
											2012-05-04 14:01:52 +10:00
										 |  |  | 	if (ret == 0) { | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 		BEGIN_NV04(chan, NvSubCopy, 0x0000, 1); | 
					
						
							|  |  |  | 		OUT_RING  (chan, handle); | 
					
						
							|  |  |  | 		BEGIN_NV04(chan, NvSubCopy, 0x0180, 1); | 
					
						
							|  |  |  | 		OUT_RING  (chan, NvNotify0); | 
					
						
							| 
									
										
										
										
											2012-05-04 14:01:52 +10:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-16 09:10:20 +10:00
										 |  |  | static inline uint32_t | 
					
						
							|  |  |  | nouveau_bo_mem_ctxdma(struct ttm_buffer_object *bo, | 
					
						
							|  |  |  | 		      struct nouveau_channel *chan, struct ttm_mem_reg *mem) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (mem->mem_type == TTM_PL_TT) | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 		return NvDmaTT; | 
					
						
							|  |  |  | 	return NvDmaFB; | 
					
						
							| 
									
										
										
										
											2011-02-16 09:10:20 +10:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-26 11:32:01 +10:00
										 |  |  | static int | 
					
						
							|  |  |  | nv04_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, | 
					
						
							|  |  |  | 		  struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-08-05 10:48:18 +10:00
										 |  |  | 	u32 src_offset = old_mem->start << PAGE_SHIFT; | 
					
						
							|  |  |  | 	u32 dst_offset = new_mem->start << PAGE_SHIFT; | 
					
						
							| 
									
										
										
										
											2010-08-26 11:32:01 +10:00
										 |  |  | 	u32 page_count = new_mem->num_pages; | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = RING_SPACE(chan, 3); | 
					
						
							|  |  |  | 	if (ret) | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-04 14:01:52 +10:00
										 |  |  | 	BEGIN_NV04(chan, NvSubCopy, NV_MEMORY_TO_MEMORY_FORMAT_DMA_SOURCE, 2); | 
					
						
							| 
									
										
										
										
											2010-08-26 11:32:01 +10:00
										 |  |  | 	OUT_RING  (chan, nouveau_bo_mem_ctxdma(bo, chan, old_mem)); | 
					
						
							|  |  |  | 	OUT_RING  (chan, nouveau_bo_mem_ctxdma(bo, chan, new_mem)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 	page_count = new_mem->num_pages; | 
					
						
							|  |  |  | 	while (page_count) { | 
					
						
							|  |  |  | 		int line_count = (page_count > 2047) ? 2047 : page_count; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ret = RING_SPACE(chan, 11); | 
					
						
							|  |  |  | 		if (ret) | 
					
						
							|  |  |  | 			return ret; | 
					
						
							| 
									
										
										
										
											2010-08-26 11:32:01 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-04 14:01:52 +10:00
										 |  |  | 		BEGIN_NV04(chan, NvSubCopy, | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 				 NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8); | 
					
						
							| 
									
										
										
										
											2010-08-26 11:32:01 +10:00
										 |  |  | 		OUT_RING  (chan, src_offset); | 
					
						
							|  |  |  | 		OUT_RING  (chan, dst_offset); | 
					
						
							|  |  |  | 		OUT_RING  (chan, PAGE_SIZE); /* src_pitch */ | 
					
						
							|  |  |  | 		OUT_RING  (chan, PAGE_SIZE); /* dst_pitch */ | 
					
						
							|  |  |  | 		OUT_RING  (chan, PAGE_SIZE); /* line_length */ | 
					
						
							|  |  |  | 		OUT_RING  (chan, line_count); | 
					
						
							|  |  |  | 		OUT_RING  (chan, 0x00000101); | 
					
						
							|  |  |  | 		OUT_RING  (chan, 0x00000000); | 
					
						
							| 
									
										
										
										
											2012-05-04 14:01:52 +10:00
										 |  |  | 		BEGIN_NV04(chan, NvSubCopy, NV_MEMORY_TO_MEMORY_FORMAT_NOP, 1); | 
					
						
							| 
									
										
										
										
											2010-08-26 11:32:01 +10:00
										 |  |  | 		OUT_RING  (chan, 0); | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		page_count -= line_count; | 
					
						
							|  |  |  | 		src_offset += (PAGE_SIZE * line_count); | 
					
						
							|  |  |  | 		dst_offset += (PAGE_SIZE * line_count); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-26 11:32:01 +10:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-06 20:54:42 +10:00
										 |  |  | static int | 
					
						
							|  |  |  | nouveau_vma_getmap(struct nouveau_channel *chan, struct nouveau_bo *nvbo, | 
					
						
							|  |  |  | 		   struct ttm_mem_reg *mem, struct nouveau_vma *vma) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct nouveau_mem *node = mem->mm_node; | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	ret = nouveau_vm_get(nv_client(chan->cli)->vm, mem->num_pages << | 
					
						
							|  |  |  | 			     PAGE_SHIFT, node->page_shift, | 
					
						
							|  |  |  | 			     NV_MEM_ACCESS_RW, vma); | 
					
						
							| 
									
										
										
										
											2011-06-06 20:54:42 +10:00
										 |  |  | 	if (ret) | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (mem->mem_type == TTM_PL_VRAM) | 
					
						
							|  |  |  | 		nouveau_vm_map(vma, node); | 
					
						
							|  |  |  | 	else | 
					
						
							| 
									
										
										
										
											2011-12-22 15:20:21 +10:00
										 |  |  | 		nouveau_vm_map_sg(vma, 0, mem->num_pages << PAGE_SHIFT, node); | 
					
						
							| 
									
										
										
										
											2011-06-06 20:54:42 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-26 11:32:01 +10:00
										 |  |  | static int | 
					
						
							|  |  |  | nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr, | 
					
						
							| 
									
										
										
										
											2012-11-28 11:25:44 +00:00
										 |  |  | 		     bool no_wait_gpu, struct ttm_mem_reg *new_mem) | 
					
						
							| 
									
										
										
										
											2010-08-26 11:32:01 +10:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	struct nouveau_drm *drm = nouveau_bdev(bo->bdev); | 
					
						
							|  |  |  | 	struct nouveau_channel *chan = chan = drm->channel; | 
					
						
							| 
									
										
										
										
											2010-08-26 11:32:01 +10:00
										 |  |  | 	struct nouveau_bo *nvbo = nouveau_bo(bo); | 
					
						
							| 
									
										
										
										
											2011-02-10 11:22:12 +10:00
										 |  |  | 	struct ttm_mem_reg *old_mem = &bo->mem; | 
					
						
							| 
									
										
										
										
											2010-08-26 11:32:01 +10:00
										 |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	mutex_lock(&chan->cli->mutex); | 
					
						
							| 
									
										
										
										
											2010-08-26 11:32:01 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-06 20:54:42 +10:00
										 |  |  | 	/* create temporary vmas for the transfer and attach them to the
 | 
					
						
							|  |  |  | 	 * old nouveau_mem node, these will get cleaned up after ttm has | 
					
						
							|  |  |  | 	 * destroyed the ttm_mem_reg | 
					
						
							| 
									
										
										
										
											2011-02-10 11:22:12 +10:00
										 |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	if (nv_device(drm->device)->card_type >= NV_50) { | 
					
						
							| 
									
										
										
										
											2011-02-10 12:22:52 +10:00
										 |  |  | 		struct nouveau_mem *node = old_mem->mm_node; | 
					
						
							| 
									
										
										
										
											2011-02-10 11:22:12 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-06 20:54:42 +10:00
										 |  |  | 		ret = nouveau_vma_getmap(chan, nvbo, old_mem, &node->vma[0]); | 
					
						
							|  |  |  | 		if (ret) | 
					
						
							|  |  |  | 			goto out; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ret = nouveau_vma_getmap(chan, nvbo, new_mem, &node->vma[1]); | 
					
						
							|  |  |  | 		if (ret) | 
					
						
							|  |  |  | 			goto out; | 
					
						
							| 
									
										
										
										
											2011-02-10 11:22:12 +10:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	ret = drm->ttm.move(chan, bo, &bo->mem, new_mem); | 
					
						
							| 
									
										
										
										
											2010-10-05 16:53:48 +10:00
										 |  |  | 	if (ret == 0) { | 
					
						
							|  |  |  | 		ret = nouveau_bo_move_accel_cleanup(chan, nvbo, evict, | 
					
						
							|  |  |  | 						    no_wait_gpu, new_mem); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-08-26 11:32:01 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-10 11:22:12 +10:00
										 |  |  | out: | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	mutex_unlock(&chan->cli->mutex); | 
					
						
							| 
									
										
										
										
											2010-10-05 16:53:48 +10:00
										 |  |  | 	return ret; | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-04 14:01:52 +10:00
										 |  |  | void | 
					
						
							| 
									
										
										
										
											2012-08-06 19:38:25 +10:00
										 |  |  | nouveau_bo_move_init(struct nouveau_drm *drm) | 
					
						
							| 
									
										
										
										
											2012-05-04 14:01:52 +10:00
										 |  |  | { | 
					
						
							|  |  |  | 	static const struct { | 
					
						
							|  |  |  | 		const char *name; | 
					
						
							| 
									
										
										
										
											2012-05-04 15:17:28 +10:00
										 |  |  | 		int engine; | 
					
						
							| 
									
										
										
										
											2012-05-04 14:01:52 +10:00
										 |  |  | 		u32 oclass; | 
					
						
							|  |  |  | 		int (*exec)(struct nouveau_channel *, | 
					
						
							|  |  |  | 			    struct ttm_buffer_object *, | 
					
						
							|  |  |  | 			    struct ttm_mem_reg *, struct ttm_mem_reg *); | 
					
						
							|  |  |  | 		int (*init)(struct nouveau_channel *, u32 handle); | 
					
						
							|  |  |  | 	} _methods[] = { | 
					
						
							| 
									
										
										
										
											2012-08-06 19:38:25 +10:00
										 |  |  | 		{  "COPY", 0, 0xa0b5, nve0_bo_move_copy, nve0_bo_move_init }, | 
					
						
							|  |  |  | 		{  "GRCE", 0, 0xa0b5, nve0_bo_move_copy, nvc0_bo_move_init }, | 
					
						
							| 
									
										
										
										
											2012-05-04 15:17:28 +10:00
										 |  |  | 		{ "COPY1", 5, 0x90b8, nvc0_bo_move_copy, nvc0_bo_move_init }, | 
					
						
							|  |  |  | 		{ "COPY0", 4, 0x90b5, nvc0_bo_move_copy, nvc0_bo_move_init }, | 
					
						
							|  |  |  | 		{  "COPY", 0, 0x85b5, nva3_bo_move_copy, nv50_bo_move_init }, | 
					
						
							|  |  |  | 		{ "CRYPT", 0, 0x74c1, nv84_bo_move_exec, nv50_bo_move_init }, | 
					
						
							|  |  |  | 		{  "M2MF", 0, 0x9039, nvc0_bo_move_m2mf, nvc0_bo_move_init }, | 
					
						
							|  |  |  | 		{  "M2MF", 0, 0x5039, nv50_bo_move_m2mf, nv50_bo_move_init }, | 
					
						
							|  |  |  | 		{  "M2MF", 0, 0x0039, nv04_bo_move_m2mf, nv04_bo_move_init }, | 
					
						
							| 
									
										
										
										
											2012-05-04 14:34:16 +10:00
										 |  |  | 		{}, | 
					
						
							| 
									
										
										
										
											2012-05-04 15:17:28 +10:00
										 |  |  | 		{ "CRYPT", 0, 0x88b4, nv98_bo_move_exec, nv50_bo_move_init }, | 
					
						
							| 
									
										
										
										
											2012-05-04 14:01:52 +10:00
										 |  |  | 	}, *mthd = _methods; | 
					
						
							|  |  |  | 	const char *name = "CPU"; | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	do { | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 		struct nouveau_object *object; | 
					
						
							| 
									
										
										
										
											2012-08-06 19:38:25 +10:00
										 |  |  | 		struct nouveau_channel *chan; | 
					
						
							| 
									
										
										
										
											2012-05-04 15:17:28 +10:00
										 |  |  | 		u32 handle = (mthd->engine << 16) | mthd->oclass; | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-06 19:38:25 +10:00
										 |  |  | 		if (mthd->init == nve0_bo_move_init) | 
					
						
							|  |  |  | 			chan = drm->cechan; | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			chan = drm->channel; | 
					
						
							|  |  |  | 		if (chan == NULL) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ret = nouveau_object_new(nv_object(drm), chan->handle, handle, | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 					 mthd->oclass, NULL, 0, &object); | 
					
						
							| 
									
										
										
										
											2012-05-04 14:01:52 +10:00
										 |  |  | 		if (ret == 0) { | 
					
						
							| 
									
										
										
										
											2012-05-04 15:17:28 +10:00
										 |  |  | 			ret = mthd->init(chan, handle); | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 			if (ret) { | 
					
						
							| 
									
										
										
										
											2012-08-06 19:38:25 +10:00
										 |  |  | 				nouveau_object_del(nv_object(drm), | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 						   chan->handle, handle); | 
					
						
							|  |  |  | 				continue; | 
					
						
							| 
									
										
										
										
											2012-05-04 14:01:52 +10:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			drm->ttm.move = mthd->exec; | 
					
						
							|  |  |  | 			name = mthd->name; | 
					
						
							|  |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2012-05-04 14:01:52 +10:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} while ((++mthd)->exec); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	NV_INFO(drm, "MM: using %s for buffer copies\n", name); | 
					
						
							| 
									
										
										
										
											2012-05-04 14:01:52 +10:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | static int | 
					
						
							|  |  |  | nouveau_bo_move_flipd(struct ttm_buffer_object *bo, bool evict, bool intr, | 
					
						
							| 
									
										
										
										
											2012-11-28 11:25:44 +00:00
										 |  |  | 		      bool no_wait_gpu, struct ttm_mem_reg *new_mem) | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | { | 
					
						
							|  |  |  | 	u32 placement_memtype = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING; | 
					
						
							|  |  |  | 	struct ttm_placement placement; | 
					
						
							|  |  |  | 	struct ttm_mem_reg tmp_mem; | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	placement.fpfn = placement.lpfn = 0; | 
					
						
							|  |  |  | 	placement.num_placement = placement.num_busy_placement = 1; | 
					
						
							| 
									
										
										
										
											2009-12-16 19:05:00 +01:00
										 |  |  | 	placement.placement = placement.busy_placement = &placement_memtype; | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	tmp_mem = *new_mem; | 
					
						
							|  |  |  | 	tmp_mem.mm_node = NULL; | 
					
						
							| 
									
										
										
										
											2012-11-28 11:25:44 +00:00
										 |  |  | 	ret = ttm_bo_mem_space(bo, &placement, &tmp_mem, intr, no_wait_gpu); | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 	if (ret) | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = ttm_tt_bind(bo->ttm, &tmp_mem); | 
					
						
							|  |  |  | 	if (ret) | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-28 11:25:44 +00:00
										 |  |  | 	ret = nouveau_bo_move_m2mf(bo, true, intr, no_wait_gpu, &tmp_mem); | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 	if (ret) | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-28 11:25:44 +00:00
										 |  |  | 	ret = ttm_bo_move_ttm(bo, true, no_wait_gpu, new_mem); | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | out: | 
					
						
							| 
									
										
										
										
											2010-08-04 12:07:08 +10:00
										 |  |  | 	ttm_bo_mem_put(bo, &tmp_mem); | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | nouveau_bo_move_flips(struct ttm_buffer_object *bo, bool evict, bool intr, | 
					
						
							| 
									
										
										
										
											2012-11-28 11:25:44 +00:00
										 |  |  | 		      bool no_wait_gpu, struct ttm_mem_reg *new_mem) | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | { | 
					
						
							|  |  |  | 	u32 placement_memtype = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING; | 
					
						
							|  |  |  | 	struct ttm_placement placement; | 
					
						
							|  |  |  | 	struct ttm_mem_reg tmp_mem; | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	placement.fpfn = placement.lpfn = 0; | 
					
						
							|  |  |  | 	placement.num_placement = placement.num_busy_placement = 1; | 
					
						
							| 
									
										
										
										
											2009-12-16 19:05:00 +01:00
										 |  |  | 	placement.placement = placement.busy_placement = &placement_memtype; | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	tmp_mem = *new_mem; | 
					
						
							|  |  |  | 	tmp_mem.mm_node = NULL; | 
					
						
							| 
									
										
										
										
											2012-11-28 11:25:44 +00:00
										 |  |  | 	ret = ttm_bo_mem_space(bo, &placement, &tmp_mem, intr, no_wait_gpu); | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 	if (ret) | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-28 11:25:44 +00:00
										 |  |  | 	ret = ttm_bo_move_ttm(bo, true, no_wait_gpu, &tmp_mem); | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 	if (ret) | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-28 11:25:44 +00:00
										 |  |  | 	ret = nouveau_bo_move_m2mf(bo, true, intr, no_wait_gpu, new_mem); | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 	if (ret) | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | out: | 
					
						
							| 
									
										
										
										
											2010-08-04 12:07:08 +10:00
										 |  |  | 	ttm_bo_mem_put(bo, &tmp_mem); | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-10 10:35:16 +10:00
										 |  |  | static void | 
					
						
							|  |  |  | nouveau_bo_move_ntfy(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_mem) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct nouveau_bo *nvbo = nouveau_bo(bo); | 
					
						
							| 
									
										
										
										
											2011-06-06 14:07:04 +10:00
										 |  |  | 	struct nouveau_vma *vma; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												drm/ttm: fix two regressions since move_notify changes
Both changes in dc97b3409a790d2a21aac6e5cdb99558b5944119 cause serious
regressions in the nouveau driver.
move_notify() was originally able to presume that bo->mem is the old node,
and new_mem is the new node.  The above commit moves the call to
move_notify() to after move() has been done, which means that now, sometimes,
new_mem isn't the new node at all, bo->mem is, and new_mem points at a
stale, possibly-just-been-killed-by-move node.
This is clearly not a good situation.  This patch reverts this change, and
replaces it with a cleanup in the move() failure path instead.
The second issue is that the call to move_notify() from cleanup_memtype_use()
causes the TTM ghost objects to get passed into the driver.  This is clearly
bad as the driver knows nothing about these "fake" TTM BOs, and ends up
accessing uninitialised memory.
I worked around this in nouveau's move_notify() hook by ensuring the BO
destructor was nouveau's.  I don't particularly like this solution, and
would rather TTM never pass the driver these objects.  However, I don't
clearly understand the reason why we're calling move_notify() here anyway
and am happy to work around the problem in nouveau instead of breaking the
behaviour expected by other drivers.
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com>
Cc: Jerome Glisse <j.glisse@gmail.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
											
										 
											2012-01-25 15:34:22 +10:00
										 |  |  | 	/* ttm can now (stupidly) pass the driver bos it didn't create... */ | 
					
						
							|  |  |  | 	if (bo->destroy != nouveau_bo_del_ttm) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-06 14:07:04 +10:00
										 |  |  | 	list_for_each_entry(vma, &nvbo->vma_list, head) { | 
					
						
							| 
									
										
										
										
											2011-11-18 11:47:03 -05:00
										 |  |  | 		if (new_mem && new_mem->mem_type == TTM_PL_VRAM) { | 
					
						
							| 
									
										
										
										
											2011-06-06 14:07:04 +10:00
										 |  |  | 			nouveau_vm_map(vma, new_mem->mm_node); | 
					
						
							|  |  |  | 		} else | 
					
						
							| 
									
										
										
										
											2011-11-18 11:47:03 -05:00
										 |  |  | 		if (new_mem && new_mem->mem_type == TTM_PL_TT && | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 		    nvbo->page_shift == vma->vm->vmm->spg_shift) { | 
					
						
							| 
									
										
										
										
											2012-04-02 11:53:06 +01:00
										 |  |  | 			if (((struct nouveau_mem *)new_mem->mm_node)->sg) | 
					
						
							|  |  |  | 				nouveau_vm_map_sg_table(vma, 0, new_mem-> | 
					
						
							|  |  |  | 						  num_pages << PAGE_SHIFT, | 
					
						
							|  |  |  | 						  new_mem->mm_node); | 
					
						
							|  |  |  | 			else | 
					
						
							|  |  |  | 				nouveau_vm_map_sg(vma, 0, new_mem-> | 
					
						
							|  |  |  | 						  num_pages << PAGE_SHIFT, | 
					
						
							|  |  |  | 						  new_mem->mm_node); | 
					
						
							| 
									
										
										
										
											2011-06-06 14:07:04 +10:00
										 |  |  | 		} else { | 
					
						
							|  |  |  | 			nouveau_vm_unmap(vma); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2011-02-10 10:35:16 +10:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | static int | 
					
						
							| 
									
										
										
										
											2009-12-11 16:51:09 +01:00
										 |  |  | nouveau_bo_vm_bind(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_mem, | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 		   struct nouveau_drm_tile **new_tile) | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	struct nouveau_drm *drm = nouveau_bdev(bo->bdev); | 
					
						
							|  |  |  | 	struct drm_device *dev = drm->dev; | 
					
						
							| 
									
										
										
										
											2009-12-11 16:51:09 +01:00
										 |  |  | 	struct nouveau_bo *nvbo = nouveau_bo(bo); | 
					
						
							| 
									
										
										
										
											2011-02-10 10:35:16 +10:00
										 |  |  | 	u64 offset = new_mem->start << PAGE_SHIFT; | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-10 10:35:16 +10:00
										 |  |  | 	*new_tile = NULL; | 
					
						
							|  |  |  | 	if (new_mem->mem_type != TTM_PL_VRAM) | 
					
						
							| 
									
										
										
										
											2009-12-11 16:51:09 +01:00
										 |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	if (nv_device(drm->device)->card_type >= NV_10) { | 
					
						
							| 
									
										
										
										
											2012-07-19 17:54:21 +10:00
										 |  |  | 		*new_tile = nv10_bo_set_tiling(dev, offset, new_mem->size, | 
					
						
							| 
									
										
										
										
											2010-10-24 16:14:41 +02:00
										 |  |  | 						nvbo->tile_mode, | 
					
						
							|  |  |  | 						nvbo->tile_flags); | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-11 16:51:09 +01:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | nouveau_bo_vm_cleanup(struct ttm_buffer_object *bo, | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 		      struct nouveau_drm_tile *new_tile, | 
					
						
							|  |  |  | 		      struct nouveau_drm_tile **old_tile) | 
					
						
							| 
									
										
										
										
											2009-12-11 16:51:09 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	struct nouveau_drm *drm = nouveau_bdev(bo->bdev); | 
					
						
							|  |  |  | 	struct drm_device *dev = drm->dev; | 
					
						
							| 
									
										
										
										
											2009-12-11 16:51:09 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-19 17:54:21 +10:00
										 |  |  | 	nv10_bo_put_tile_region(dev, *old_tile, bo->sync_obj); | 
					
						
							| 
									
										
										
										
											2011-02-10 10:35:16 +10:00
										 |  |  | 	*old_tile = new_tile; | 
					
						
							| 
									
										
										
										
											2009-12-11 16:51:09 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr, | 
					
						
							| 
									
										
										
										
											2012-11-28 11:25:44 +00:00
										 |  |  | 		bool no_wait_gpu, struct ttm_mem_reg *new_mem) | 
					
						
							| 
									
										
										
										
											2009-12-11 16:51:09 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	struct nouveau_drm *drm = nouveau_bdev(bo->bdev); | 
					
						
							| 
									
										
										
										
											2009-12-11 16:51:09 +01:00
										 |  |  | 	struct nouveau_bo *nvbo = nouveau_bo(bo); | 
					
						
							|  |  |  | 	struct ttm_mem_reg *old_mem = &bo->mem; | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	struct nouveau_drm_tile *new_tile = NULL; | 
					
						
							| 
									
										
										
										
											2009-12-11 16:51:09 +01:00
										 |  |  | 	int ret = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	if (nv_device(drm->device)->card_type < NV_50) { | 
					
						
							| 
									
										
										
										
											2011-02-10 10:35:16 +10:00
										 |  |  | 		ret = nouveau_bo_vm_bind(bo, new_mem, &new_tile); | 
					
						
							|  |  |  | 		if (ret) | 
					
						
							|  |  |  | 			return ret; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-12-11 16:51:09 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Fake bo copy. */ | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 	if (old_mem->mem_type == TTM_PL_SYSTEM && !bo->ttm) { | 
					
						
							|  |  |  | 		BUG_ON(bo->mem.mm_node != NULL); | 
					
						
							|  |  |  | 		bo->mem = *new_mem; | 
					
						
							|  |  |  | 		new_mem->mm_node = NULL; | 
					
						
							| 
									
										
										
										
											2009-12-11 16:51:09 +01:00
										 |  |  | 		goto out; | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-04 14:01:52 +10:00
										 |  |  | 	/* CPU copy if we have no accelerated method available */ | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	if (!drm->ttm.move) { | 
					
						
							| 
									
										
										
										
											2012-11-28 11:25:44 +00:00
										 |  |  | 		ret = ttm_bo_move_memcpy(bo, evict, no_wait_gpu, new_mem); | 
					
						
							| 
									
										
										
										
											2010-08-27 11:55:43 +10:00
										 |  |  | 		goto out; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-11 16:51:09 +01:00
										 |  |  | 	/* Hardware assisted copy. */ | 
					
						
							|  |  |  | 	if (new_mem->mem_type == TTM_PL_SYSTEM) | 
					
						
							| 
									
										
										
										
											2012-11-28 11:25:44 +00:00
										 |  |  | 		ret = nouveau_bo_move_flipd(bo, evict, intr, | 
					
						
							|  |  |  | 					    no_wait_gpu, new_mem); | 
					
						
							| 
									
										
										
										
											2009-12-11 16:51:09 +01:00
										 |  |  | 	else if (old_mem->mem_type == TTM_PL_SYSTEM) | 
					
						
							| 
									
										
										
										
											2012-11-28 11:25:44 +00:00
										 |  |  | 		ret = nouveau_bo_move_flips(bo, evict, intr, | 
					
						
							|  |  |  | 					    no_wait_gpu, new_mem); | 
					
						
							| 
									
										
										
										
											2009-12-11 16:51:09 +01:00
										 |  |  | 	else | 
					
						
							| 
									
										
										
										
											2012-11-28 11:25:44 +00:00
										 |  |  | 		ret = nouveau_bo_move_m2mf(bo, evict, intr, | 
					
						
							|  |  |  | 					   no_wait_gpu, new_mem); | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-11 16:51:09 +01:00
										 |  |  | 	if (!ret) | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Fallback to software copy. */ | 
					
						
							| 
									
										
										
										
											2012-11-28 11:25:44 +00:00
										 |  |  | 	ret = ttm_bo_move_memcpy(bo, evict, no_wait_gpu, new_mem); | 
					
						
							| 
									
										
										
										
											2009-12-11 16:51:09 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | out: | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	if (nv_device(drm->device)->card_type < NV_50) { | 
					
						
							| 
									
										
										
										
											2011-02-10 10:35:16 +10:00
										 |  |  | 		if (ret) | 
					
						
							|  |  |  | 			nouveau_bo_vm_cleanup(bo, NULL, &new_tile); | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			nouveau_bo_vm_cleanup(bo, new_tile, &nvbo->tile); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-12-11 16:51:09 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return ret; | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | nouveau_bo_verify_access(struct ttm_buffer_object *bo, struct file *filp) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-09 14:39:25 +02:00
										 |  |  | static int | 
					
						
							|  |  |  | nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	struct nouveau_drm *drm = nouveau_bdev(bdev); | 
					
						
							|  |  |  | 	struct drm_device *dev = drm->dev; | 
					
						
							| 
									
										
										
										
											2010-11-15 11:53:16 +10:00
										 |  |  | 	int ret; | 
					
						
							| 
									
										
										
										
											2010-04-09 14:39:25 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	mem->bus.addr = NULL; | 
					
						
							|  |  |  | 	mem->bus.offset = 0; | 
					
						
							|  |  |  | 	mem->bus.size = mem->num_pages << PAGE_SHIFT; | 
					
						
							|  |  |  | 	mem->bus.base = 0; | 
					
						
							|  |  |  | 	mem->bus.is_iomem = false; | 
					
						
							|  |  |  | 	if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE)) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	switch (mem->mem_type) { | 
					
						
							|  |  |  | 	case TTM_PL_SYSTEM: | 
					
						
							|  |  |  | 		/* System memory */ | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	case TTM_PL_TT: | 
					
						
							|  |  |  | #if __OS_HAS_AGP
 | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 		if (drm->agp.stat == ENABLED) { | 
					
						
							| 
									
										
										
										
											2010-08-05 10:48:18 +10:00
										 |  |  | 			mem->bus.offset = mem->start << PAGE_SHIFT; | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 			mem->bus.base = drm->agp.base; | 
					
						
							| 
									
										
										
										
											2012-12-31 03:34:59 +02:00
										 |  |  | 			mem->bus.is_iomem = !dev->agp->cant_use_aperture; | 
					
						
							| 
									
										
										
										
											2010-04-09 14:39:25 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case TTM_PL_VRAM: | 
					
						
							| 
									
										
										
										
											2012-07-14 19:09:17 +10:00
										 |  |  | 		mem->bus.offset = mem->start << PAGE_SHIFT; | 
					
						
							|  |  |  | 		mem->bus.base = pci_resource_start(dev->pdev, 1); | 
					
						
							|  |  |  | 		mem->bus.is_iomem = true; | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 		if (nv_device(drm->device)->card_type >= NV_50) { | 
					
						
							|  |  |  | 			struct nouveau_bar *bar = nouveau_bar(drm->device); | 
					
						
							| 
									
										
										
										
											2012-07-14 19:09:17 +10:00
										 |  |  | 			struct nouveau_mem *node = mem->mm_node; | 
					
						
							| 
									
										
										
										
											2010-11-15 11:48:33 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 			ret = bar->umap(bar, node, NV_MEM_ACCESS_RW, | 
					
						
							| 
									
										
										
										
											2012-07-14 19:09:17 +10:00
										 |  |  | 					&node->bar_vma); | 
					
						
							|  |  |  | 			if (ret) | 
					
						
							|  |  |  | 				return ret; | 
					
						
							| 
									
										
										
										
											2010-11-15 11:53:16 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-14 19:09:17 +10:00
										 |  |  | 			mem->bus.offset = node->bar_vma.offset; | 
					
						
							| 
									
										
										
										
											2010-11-15 11:53:16 +10:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2010-04-09 14:39:25 +02:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | nouveau_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	struct nouveau_drm *drm = nouveau_bdev(bdev); | 
					
						
							|  |  |  | 	struct nouveau_bar *bar = nouveau_bar(drm->device); | 
					
						
							| 
									
										
										
										
											2011-02-10 12:22:52 +10:00
										 |  |  | 	struct nouveau_mem *node = mem->mm_node; | 
					
						
							| 
									
										
										
										
											2010-11-15 11:53:16 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-10 12:22:52 +10:00
										 |  |  | 	if (!node->bar_vma.node) | 
					
						
							| 
									
										
										
										
											2010-11-15 11:53:16 +10:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	bar->unmap(bar, &node->bar_vma); | 
					
						
							| 
									
										
										
										
											2010-04-09 14:39:25 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	struct nouveau_drm *drm = nouveau_bdev(bo->bdev); | 
					
						
							| 
									
										
										
										
											2010-09-10 11:12:25 +10:00
										 |  |  | 	struct nouveau_bo *nvbo = nouveau_bo(bo); | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	struct nouveau_device *device = nv_device(drm->device); | 
					
						
							|  |  |  | 	u32 mappable = pci_resource_len(device->pdev, 1) >> PAGE_SHIFT; | 
					
						
							| 
									
										
										
										
											2010-09-10 11:12:25 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* as long as the bo isn't in vram, and isn't tiled, we've got
 | 
					
						
							|  |  |  | 	 * nothing to do here. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if (bo->mem.mem_type != TTM_PL_VRAM) { | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 		if (nv_device(drm->device)->card_type < NV_50 || | 
					
						
							| 
									
										
										
										
											2010-10-10 06:01:08 +02:00
										 |  |  | 		    !nouveau_bo_tile_layout(nvbo)) | 
					
						
							| 
									
										
										
										
											2010-09-10 11:12:25 +10:00
										 |  |  | 			return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* make sure bo is in mappable vram */ | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	if (bo->mem.start + bo->mem.num_pages < mappable) | 
					
						
							| 
									
										
										
										
											2010-09-10 11:12:25 +10:00
										 |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	nvbo->placement.fpfn = 0; | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	nvbo->placement.lpfn = mappable; | 
					
						
							| 
									
										
										
										
											2012-05-18 15:31:12 +01:00
										 |  |  | 	nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_VRAM, 0); | 
					
						
							| 
									
										
										
										
											2012-11-28 11:25:44 +00:00
										 |  |  | 	return nouveau_bo_validate(nvbo, false, false); | 
					
						
							| 
									
										
										
										
											2010-04-09 14:39:25 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-17 17:14:26 -04:00
										 |  |  | static int | 
					
						
							|  |  |  | nouveau_ttm_tt_populate(struct ttm_tt *ttm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-11-09 17:15:26 -05:00
										 |  |  | 	struct ttm_dma_tt *ttm_dma = (void *)ttm; | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	struct nouveau_drm *drm; | 
					
						
							| 
									
										
										
										
											2011-10-17 17:14:26 -04:00
										 |  |  | 	struct drm_device *dev; | 
					
						
							|  |  |  | 	unsigned i; | 
					
						
							|  |  |  | 	int r; | 
					
						
							| 
									
										
										
										
											2012-04-02 11:53:06 +01:00
										 |  |  | 	bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG); | 
					
						
							| 
									
										
										
										
											2011-10-17 17:14:26 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (ttm->state != tt_unpopulated) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-02 11:53:06 +01:00
										 |  |  | 	if (slave && ttm->sg) { | 
					
						
							|  |  |  | 		/* make userspace faulting work */ | 
					
						
							|  |  |  | 		drm_prime_sg_to_page_addr_arrays(ttm->sg, ttm->pages, | 
					
						
							|  |  |  | 						 ttm_dma->dma_address, ttm->num_pages); | 
					
						
							|  |  |  | 		ttm->state = tt_unbound; | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	drm = nouveau_bdev(ttm->bdev); | 
					
						
							|  |  |  | 	dev = drm->dev; | 
					
						
							| 
									
										
										
										
											2011-10-17 17:14:26 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-03 17:37:37 -05:00
										 |  |  | #if __OS_HAS_AGP
 | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	if (drm->agp.stat == ENABLED) { | 
					
						
							| 
									
										
										
										
											2012-01-03 17:37:37 -05:00
										 |  |  | 		return ttm_agp_tt_populate(ttm); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-17 17:14:26 -04:00
										 |  |  | #ifdef CONFIG_SWIOTLB
 | 
					
						
							|  |  |  | 	if (swiotlb_nr_tbl()) { | 
					
						
							| 
									
										
										
										
											2011-11-09 17:15:26 -05:00
										 |  |  | 		return ttm_dma_populate((void *)ttm, dev->dev); | 
					
						
							| 
									
										
										
										
											2011-10-17 17:14:26 -04:00
										 |  |  | 	} | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	r = ttm_pool_populate(ttm); | 
					
						
							|  |  |  | 	if (r) { | 
					
						
							|  |  |  | 		return r; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; i < ttm->num_pages; i++) { | 
					
						
							| 
									
										
										
										
											2011-11-09 17:15:26 -05:00
										 |  |  | 		ttm_dma->dma_address[i] = pci_map_page(dev->pdev, ttm->pages[i], | 
					
						
							| 
									
										
										
										
											2011-10-17 17:14:26 -04:00
										 |  |  | 						   0, PAGE_SIZE, | 
					
						
							|  |  |  | 						   PCI_DMA_BIDIRECTIONAL); | 
					
						
							| 
									
										
										
										
											2011-11-09 17:15:26 -05:00
										 |  |  | 		if (pci_dma_mapping_error(dev->pdev, ttm_dma->dma_address[i])) { | 
					
						
							| 
									
										
										
										
											2011-10-17 17:14:26 -04:00
										 |  |  | 			while (--i) { | 
					
						
							| 
									
										
										
										
											2011-11-09 17:15:26 -05:00
										 |  |  | 				pci_unmap_page(dev->pdev, ttm_dma->dma_address[i], | 
					
						
							| 
									
										
										
										
											2011-10-17 17:14:26 -04:00
										 |  |  | 					       PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); | 
					
						
							| 
									
										
										
										
											2011-11-09 17:15:26 -05:00
										 |  |  | 				ttm_dma->dma_address[i] = 0; | 
					
						
							| 
									
										
										
										
											2011-10-17 17:14:26 -04:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			ttm_pool_unpopulate(ttm); | 
					
						
							|  |  |  | 			return -EFAULT; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-11-09 17:15:26 -05:00
										 |  |  | 	struct ttm_dma_tt *ttm_dma = (void *)ttm; | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	struct nouveau_drm *drm; | 
					
						
							| 
									
										
										
										
											2011-10-17 17:14:26 -04:00
										 |  |  | 	struct drm_device *dev; | 
					
						
							|  |  |  | 	unsigned i; | 
					
						
							| 
									
										
										
										
											2012-04-02 11:53:06 +01:00
										 |  |  | 	bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (slave) | 
					
						
							|  |  |  | 		return; | 
					
						
							| 
									
										
										
										
											2011-10-17 17:14:26 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	drm = nouveau_bdev(ttm->bdev); | 
					
						
							|  |  |  | 	dev = drm->dev; | 
					
						
							| 
									
										
										
										
											2011-10-17 17:14:26 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-03 17:37:37 -05:00
										 |  |  | #if __OS_HAS_AGP
 | 
					
						
							| 
									
										
										
										
											2012-07-20 08:17:34 +10:00
										 |  |  | 	if (drm->agp.stat == ENABLED) { | 
					
						
							| 
									
										
										
										
											2012-01-03 17:37:37 -05:00
										 |  |  | 		ttm_agp_tt_unpopulate(ttm); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-17 17:14:26 -04:00
										 |  |  | #ifdef CONFIG_SWIOTLB
 | 
					
						
							|  |  |  | 	if (swiotlb_nr_tbl()) { | 
					
						
							| 
									
										
										
										
											2011-11-09 17:15:26 -05:00
										 |  |  | 		ttm_dma_unpopulate((void *)ttm, dev->dev); | 
					
						
							| 
									
										
										
										
											2011-10-17 17:14:26 -04:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; i < ttm->num_pages; i++) { | 
					
						
							| 
									
										
										
										
											2011-11-09 17:15:26 -05:00
										 |  |  | 		if (ttm_dma->dma_address[i]) { | 
					
						
							|  |  |  | 			pci_unmap_page(dev->pdev, ttm_dma->dma_address[i], | 
					
						
							| 
									
										
										
										
											2011-10-17 17:14:26 -04:00
										 |  |  | 				       PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ttm_pool_unpopulate(ttm); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-30 12:51:48 +10:00
										 |  |  | void | 
					
						
							|  |  |  | nouveau_bo_fence(struct nouveau_bo *nvbo, struct nouveau_fence *fence) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct nouveau_fence *old_fence = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (likely(fence)) | 
					
						
							|  |  |  | 		nouveau_fence_ref(fence); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	spin_lock(&nvbo->bo.bdev->fence_lock); | 
					
						
							|  |  |  | 	old_fence = nvbo->bo.sync_obj; | 
					
						
							|  |  |  | 	nvbo->bo.sync_obj = fence; | 
					
						
							|  |  |  | 	spin_unlock(&nvbo->bo.bdev->fence_lock); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	nouveau_fence_unref(&old_fence); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | nouveau_bo_fence_unref(void **sync_obj) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	nouveau_fence_unref((struct nouveau_fence **)sync_obj); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void * | 
					
						
							|  |  |  | nouveau_bo_fence_ref(void *sync_obj) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return nouveau_fence_ref(sync_obj); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool | 
					
						
							| 
									
										
										
										
											2012-10-12 15:04:00 +00:00
										 |  |  | nouveau_bo_fence_signalled(void *sync_obj) | 
					
						
							| 
									
										
										
										
											2012-04-30 12:51:48 +10:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-04-30 13:30:00 +10:00
										 |  |  | 	return nouveau_fence_done(sync_obj); | 
					
						
							| 
									
										
										
										
											2012-04-30 12:51:48 +10:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							| 
									
										
										
										
											2012-10-12 15:04:00 +00:00
										 |  |  | nouveau_bo_fence_wait(void *sync_obj, bool lazy, bool intr) | 
					
						
							| 
									
										
										
										
											2012-04-30 12:51:48 +10:00
										 |  |  | { | 
					
						
							|  |  |  | 	return nouveau_fence_wait(sync_obj, lazy, intr); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							| 
									
										
										
										
											2012-10-12 15:04:00 +00:00
										 |  |  | nouveau_bo_fence_flush(void *sync_obj) | 
					
						
							| 
									
										
										
										
											2012-04-30 12:51:48 +10:00
										 |  |  | { | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | struct ttm_bo_driver nouveau_bo_driver = { | 
					
						
							| 
									
										
										
										
											2011-11-01 20:46:13 -04:00
										 |  |  | 	.ttm_tt_create = &nouveau_ttm_tt_create, | 
					
						
							| 
									
										
										
										
											2011-10-17 17:14:26 -04:00
										 |  |  | 	.ttm_tt_populate = &nouveau_ttm_tt_populate, | 
					
						
							|  |  |  | 	.ttm_tt_unpopulate = &nouveau_ttm_tt_unpopulate, | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 	.invalidate_caches = nouveau_bo_invalidate_caches, | 
					
						
							|  |  |  | 	.init_mem_type = nouveau_bo_init_mem_type, | 
					
						
							|  |  |  | 	.evict_flags = nouveau_bo_evict_flags, | 
					
						
							| 
									
										
										
										
											2011-02-10 10:35:16 +10:00
										 |  |  | 	.move_notify = nouveau_bo_move_ntfy, | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | 	.move = nouveau_bo_move, | 
					
						
							|  |  |  | 	.verify_access = nouveau_bo_verify_access, | 
					
						
							| 
									
										
										
										
											2012-04-30 12:51:48 +10:00
										 |  |  | 	.sync_obj_signaled = nouveau_bo_fence_signalled, | 
					
						
							|  |  |  | 	.sync_obj_wait = nouveau_bo_fence_wait, | 
					
						
							|  |  |  | 	.sync_obj_flush = nouveau_bo_fence_flush, | 
					
						
							|  |  |  | 	.sync_obj_unref = nouveau_bo_fence_unref, | 
					
						
							|  |  |  | 	.sync_obj_ref = nouveau_bo_fence_ref, | 
					
						
							| 
									
										
										
										
											2010-04-09 14:39:25 +02:00
										 |  |  | 	.fault_reserve_notify = &nouveau_ttm_fault_reserve_notify, | 
					
						
							|  |  |  | 	.io_mem_reserve = &nouveau_ttm_io_mem_reserve, | 
					
						
							|  |  |  | 	.io_mem_free = &nouveau_ttm_io_mem_free, | 
					
						
							| 
									
										
										
										
											2009-12-11 19:24:15 +10:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-06 14:07:04 +10:00
										 |  |  | struct nouveau_vma * | 
					
						
							|  |  |  | nouveau_bo_vma_find(struct nouveau_bo *nvbo, struct nouveau_vm *vm) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct nouveau_vma *vma; | 
					
						
							|  |  |  | 	list_for_each_entry(vma, &nvbo->vma_list, head) { | 
					
						
							|  |  |  | 		if (vma->vm == vm) | 
					
						
							|  |  |  | 			return vma; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | nouveau_bo_vma_add(struct nouveau_bo *nvbo, struct nouveau_vm *vm, | 
					
						
							|  |  |  | 		   struct nouveau_vma *vma) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	const u32 size = nvbo->bo.mem.num_pages << PAGE_SHIFT; | 
					
						
							|  |  |  | 	struct nouveau_mem *node = nvbo->bo.mem.mm_node; | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = nouveau_vm_get(vm, size, nvbo->page_shift, | 
					
						
							|  |  |  | 			     NV_MEM_ACCESS_RW, vma); | 
					
						
							|  |  |  | 	if (ret) | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (nvbo->bo.mem.mem_type == TTM_PL_VRAM) | 
					
						
							|  |  |  | 		nouveau_vm_map(vma, nvbo->bo.mem.mm_node); | 
					
						
							| 
									
										
										
										
											2012-04-02 11:53:06 +01:00
										 |  |  | 	else if (nvbo->bo.mem.mem_type == TTM_PL_TT) { | 
					
						
							|  |  |  | 		if (node->sg) | 
					
						
							|  |  |  | 			nouveau_vm_map_sg_table(vma, 0, size, node); | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			nouveau_vm_map_sg(vma, 0, size, node); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2011-06-06 14:07:04 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	list_add_tail(&vma->head, &nvbo->vma_list); | 
					
						
							| 
									
										
										
										
											2011-06-07 15:25:12 +10:00
										 |  |  | 	vma->refcount = 1; | 
					
						
							| 
									
										
										
										
											2011-06-06 14:07:04 +10:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | nouveau_bo_vma_del(struct nouveau_bo *nvbo, struct nouveau_vma *vma) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (vma->node) { | 
					
						
							|  |  |  | 		if (nvbo->bo.mem.mem_type != TTM_PL_SYSTEM) { | 
					
						
							|  |  |  | 			spin_lock(&nvbo->bo.bdev->fence_lock); | 
					
						
							| 
									
										
										
										
											2011-10-27 18:28:37 +02:00
										 |  |  | 			ttm_bo_wait(&nvbo->bo, false, false, false); | 
					
						
							| 
									
										
										
										
											2011-06-06 14:07:04 +10:00
										 |  |  | 			spin_unlock(&nvbo->bo.bdev->fence_lock); | 
					
						
							|  |  |  | 			nouveau_vm_unmap(vma); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		nouveau_vm_put(vma); | 
					
						
							|  |  |  | 		list_del(&vma->head); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |