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 1aaf1d74..cd5f9cf8 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 @@ -359,6 +359,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 58942829..d79c1a52 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -594,7 +594,7 @@ nouveau_mem_alloc(struct drm_device *dev, int alignment, uint64_t size, * page size in the GPU VM. */ if (flags & NOUVEAU_MEM_FB && dev_priv->card_type >= NV_50) { - size = (size + (64 * 1024)) & ~((64 * 1024) - 1); + size = (size + 65535) & ~65535; if (alignment < 16) alignment = 16; } @@ -659,6 +659,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"); @@ -666,11 +667,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 { @@ -808,3 +820,53 @@ nouveau_ioctl_mem_free(struct drm_device *dev, void *data, 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; +} +