diff options
| -rw-r--r-- | shared-core/nouveau_drm.h | 20 | ||||
| -rw-r--r-- | shared-core/nouveau_drv.h | 4 | ||||
| -rw-r--r-- | shared-core/nouveau_fifo.c | 1 | ||||
| -rw-r--r-- | shared-core/nouveau_mem.c | 71 | 
4 files changed, 87 insertions, 9 deletions
| diff --git a/shared-core/nouveau_drm.h b/shared-core/nouveau_drm.h index bbb51bc4..4b5869ad 100644 --- a/shared-core/nouveau_drm.h +++ b/shared-core/nouveau_drm.h @@ -25,7 +25,7 @@  #ifndef __NOUVEAU_DRM_H__  #define __NOUVEAU_DRM_H__ -#define NOUVEAU_DRM_HEADER_PATCHLEVEL 10 +#define NOUVEAU_DRM_HEADER_PATCHLEVEL 11  struct drm_nouveau_channel_alloc {  	uint32_t     fb_ctxdma_handle; @@ -85,10 +85,12 @@ struct drm_nouveau_gpuobj_free {  #define NOUVEAU_MEM_PINNED		0x00000040  #define NOUVEAU_MEM_USER_BACKED		0x00000080  #define NOUVEAU_MEM_MAPPED		0x00000100 -#define NOUVEAU_MEM_INSTANCE		0x00000200 /* internal */ -#define NOUVEAU_MEM_NOTIFIER            0x00000400 /* internal */ -#define NOUVEAU_MEM_NOVM		0x00000800 /* internal */ -#define NOUVEAU_MEM_USER		0x00001000 /* internal */ +#define NOUVEAU_MEM_TILE		0x00000200 +#define NOUVEAU_MEM_TILE_ZETA		0x00000400 +#define NOUVEAU_MEM_INSTANCE		0x01000000 /* internal */ +#define NOUVEAU_MEM_NOTIFIER            0x02000000 /* internal */ +#define NOUVEAU_MEM_NOVM		0x04000000 /* internal */ +#define NOUVEAU_MEM_USER		0x08000000 /* internal */  #define NOUVEAU_MEM_INTERNAL (NOUVEAU_MEM_INSTANCE | \  			      NOUVEAU_MEM_NOTIFIER | \  			      NOUVEAU_MEM_NOVM | \ @@ -107,6 +109,13 @@ struct drm_nouveau_mem_free {  	int flags;  }; +struct drm_nouveau_mem_tile { +	uint64_t offset; +	uint64_t delta; +	uint64_t size; +	int flags; +}; +  /* FIXME : maybe unify {GET,SET}PARAMs */  #define NOUVEAU_GETPARAM_PCI_VENDOR      3  #define NOUVEAU_GETPARAM_PCI_DEVICE      4 @@ -168,5 +177,6 @@ struct drm_nouveau_sarea {  #define DRM_NOUVEAU_GPUOBJ_FREE        0x07  #define DRM_NOUVEAU_MEM_ALLOC          0x08  #define DRM_NOUVEAU_MEM_FREE           0x09 +#define DRM_NOUVEAU_MEM_TILE           0x0a  #endif /* __NOUVEAU_DRM_H__ */ diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h index 33e2a5b6..03fe2ba7 100644 --- a/shared-core/nouveau_drv.h +++ b/shared-core/nouveau_drv.h @@ -34,7 +34,7 @@  #define DRIVER_MAJOR		0  #define DRIVER_MINOR		0 -#define DRIVER_PATCHLEVEL	10 +#define DRIVER_PATCHLEVEL	11  #define NOUVEAU_FAMILY   0x0000FFFF  #define NOUVEAU_FLAGS    0xFFFF0000 @@ -385,6 +385,8 @@ extern int  nouveau_ioctl_mem_alloc(struct drm_device *, void *data,  				    struct drm_file *);  extern int  nouveau_ioctl_mem_free(struct drm_device *, void *data,  				   struct drm_file *); +extern int  nouveau_ioctl_mem_tile(struct drm_device *, void *data, +				   struct drm_file *);  extern struct mem_block* nouveau_mem_alloc(struct drm_device *,  					   int alignment, uint64_t size,  					   int flags, struct drm_file *); diff --git a/shared-core/nouveau_fifo.c b/shared-core/nouveau_fifo.c index d8fda277..085336af 100644 --- a/shared-core/nouveau_fifo.c +++ b/shared-core/nouveau_fifo.c @@ -593,6 +593,7 @@ struct drm_ioctl_desc nouveau_ioctls[] = {  	DRM_IOCTL_DEF(DRM_NOUVEAU_GPUOBJ_FREE, nouveau_ioctl_gpuobj_free, DRM_AUTH),  	DRM_IOCTL_DEF(DRM_NOUVEAU_MEM_ALLOC, nouveau_ioctl_mem_alloc, DRM_AUTH),  	DRM_IOCTL_DEF(DRM_NOUVEAU_MEM_FREE, nouveau_ioctl_mem_free, DRM_AUTH), +	DRM_IOCTL_DEF(DRM_NOUVEAU_MEM_TILE, nouveau_ioctl_mem_tile, DRM_AUTH),  };  int nouveau_max_ioctl = DRM_ARRAY_SIZE(nouveau_ioctls); diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c index 861d699f..db207e76 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -606,8 +606,11 @@ nouveau_mem_alloc(struct drm_device *dev, int alignment, uint64_t size,  	/* Align allocation sizes to 64KiB blocks on G8x.  We use a 64KiB  	 * page size in the GPU VM.  	 */ -	if (flags & NOUVEAU_MEM_FB && dev_priv->card_type >= NV_50) -		size = (size + (64 * 1024)) & ~((64 * 1024) - 1); +	if (flags & NOUVEAU_MEM_FB && dev_priv->card_type >= NV_50) { +		size = (size + 65535) & ~65535; +		if (alignment < 16) +			alignment = 16; +	}  	/*  	 * Warn about 0 sized allocations, but let it go through. It'll return 1 page @@ -669,6 +672,7 @@ alloc_ok:  		struct nouveau_gpuobj *pt = dev_priv->vm_vram_pt;  		unsigned offset = block->start;  		unsigned count = block->size / 65536; +		unsigned tile = 0;  		if (!pt) {  			DRM_ERROR("vm alloc without vm pt\n"); @@ -676,11 +680,22 @@ alloc_ok:  			return NULL;  		} +		/* The tiling stuff is *not* what NVIDIA does - but both the +		 * 2D and 3D engines seem happy with this simpler method. +		 * Should look into why NVIDIA do what they do at some point. +		 */ +		if (flags & NOUVEAU_MEM_TILE) { +			if (flags & NOUVEAU_MEM_TILE_ZETA) +				tile = 0x00002800; +			else +				tile = 0x00007000; +		} +  		while (count--) {  			unsigned pte = offset / 65536;  			INSTANCE_WR(pt, (pte * 2) + 0, offset | 1); -			INSTANCE_WR(pt, (pte * 2) + 1, 0x00000000); +			INSTANCE_WR(pt, (pte * 2) + 1, 0x00000000 | tile);  			offset += 65536;  		}  	} else { @@ -833,3 +848,53 @@ int nouveau_ioctl_mem_free(struct drm_device *dev, void *data, struct drm_file *  	nouveau_mem_free(dev, block);  	return 0;  } + +int +nouveau_ioctl_mem_tile(struct drm_device *dev, void *data, +		       struct drm_file *file_priv) +{ +	struct drm_nouveau_private *dev_priv = dev->dev_private; +	struct drm_nouveau_mem_tile *memtile = data; +	struct mem_block *block = NULL; + +	NOUVEAU_CHECK_INITIALISED_WITH_RETURN; + +	if (dev_priv->card_type < NV_50) +		return -EINVAL; +	 +	if (memtile->flags & NOUVEAU_MEM_FB) { +		memtile->offset -= 512*1024*1024; +		block = find_block(dev_priv->fb_heap, memtile->offset); +	} + +	if (!block) +		return -EINVAL; + +	if (block->file_priv != file_priv) +		return -EPERM; + +	{ +		struct nouveau_gpuobj *pt = dev_priv->vm_vram_pt; +		unsigned offset = block->start + memtile->delta; +		unsigned count = memtile->size / 65536; +		unsigned tile = 0; + +		if (memtile->flags & NOUVEAU_MEM_TILE) { +			if (memtile->flags & NOUVEAU_MEM_TILE_ZETA) +				tile = 0x00002800; +			else +				tile = 0x00007000; +		} + +		while (count--) { +			unsigned pte = offset / 65536; + +			INSTANCE_WR(pt, (pte * 2) + 0, offset | 1); +			INSTANCE_WR(pt, (pte * 2) + 1, 0x00000000 | tile); +			offset += 65536; +		} +	} + +	return 0; +} + | 
