Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7f4a195f authored by Ben Skeggs's avatar Ben Skeggs
Browse files

drm/nouveau: tidy up and extend dma object creation interfaces

parent 6d6c5a15
Loading
Loading
Loading
Loading
+11 −12
Original line number Diff line number Diff line
@@ -39,22 +39,22 @@ nouveau_channel_pushbuf_ctxdma_init(struct nouveau_channel *chan)

	if (dev_priv->card_type >= NV_50) {
		ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, 0,
					     dev_priv->vm_end, NV_DMA_ACCESS_RO,
					     NV_DMA_TARGET_AGP, &pushbuf);
					     dev_priv->vm_end, NV_MEM_ACCESS_RO,
					     NV_MEM_TARGET_VM, &pushbuf);
		chan->pushbuf_base = pb->bo.offset;
	} else
	if (pb->bo.mem.mem_type == TTM_PL_TT) {
		ret = nouveau_gpuobj_gart_dma_new(chan, 0,
		ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, 0,
					     dev_priv->gart_info.aper_size,
						  NV_DMA_ACCESS_RO, &pushbuf,
						  NULL);
					     NV_MEM_ACCESS_RO,
					     NV_MEM_TARGET_GART, &pushbuf);
		chan->pushbuf_base = pb->bo.mem.start << PAGE_SHIFT;
	} else
	if (dev_priv->card_type != NV_04) {
		ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, 0,
					     dev_priv->fb_available_size,
					     NV_DMA_ACCESS_RO,
					     NV_DMA_TARGET_VIDMEM, &pushbuf);
					     NV_MEM_ACCESS_RO,
					     NV_MEM_TARGET_VRAM, &pushbuf);
		chan->pushbuf_base = pb->bo.mem.start << PAGE_SHIFT;
	} else {
		/* NV04 cmdbuf hack, from original ddx.. not sure of it's
@@ -62,11 +62,10 @@ nouveau_channel_pushbuf_ctxdma_init(struct nouveau_channel *chan)
		 * VRAM.
		 */
		ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
					     pci_resource_start(dev->pdev,
					     1),
					     pci_resource_start(dev->pdev, 1),
					     dev_priv->fb_available_size,
					     NV_DMA_ACCESS_RO,
					     NV_DMA_TARGET_PCI, &pushbuf);
					     NV_MEM_ACCESS_RO,
					     NV_MEM_TARGET_PCI, &pushbuf);
		chan->pushbuf_base = pb->bo.mem.start << PAGE_SHIFT;
	}

+22 −4
Original line number Diff line number Diff line
@@ -886,12 +886,14 @@ extern int nouveau_gpuobj_new_fake(struct drm_device *, u32 pinst, u64 vinst,
extern int nouveau_gpuobj_dma_new(struct nouveau_channel *, int class,
				  uint64_t offset, uint64_t size, int access,
				  int target, struct nouveau_gpuobj **);
extern int nouveau_gpuobj_gart_dma_new(struct nouveau_channel *,
				       uint64_t offset, uint64_t size,
				       int access, struct nouveau_gpuobj **,
				       uint32_t *o_ret);
extern int nouveau_gpuobj_gr_new(struct nouveau_channel *, int class,
				 struct nouveau_gpuobj **);
extern int nv50_gpuobj_dma_new(struct nouveau_channel *, int class, u64 base,
			       u64 size, int target, int access, u32 type,
			       u32 comp, struct nouveau_gpuobj **pobj);
extern void nv50_gpuobj_dma_init(struct nouveau_gpuobj *, u32 offset,
				 int class, u64 base, u64 size, int target,
				 int access, u32 type, u32 comp);
extern int nouveau_ioctl_grobj_alloc(struct drm_device *, void *data,
				     struct drm_file *);
extern int nouveau_ioctl_gpuobj_free(struct drm_device *, void *data,
@@ -1545,6 +1547,22 @@ nv_match_device(struct drm_device *dev, unsigned device,
		dev->pdev->subsystem_device == sub_device;
}

/* memory type/access flags, do not match hardware values */
#define NV_MEM_ACCESS_RO 1
#define NV_MEM_ACCESS_WO 2
#define NV_MEM_ACCESS_RW (NV_MEM_ACCESS_RO | NV_MEM_ACCESS_WO)
#define NV_MEM_ACCESS_VM 4

#define NV_MEM_TARGET_VRAM        0
#define NV_MEM_TARGET_PCI         1
#define NV_MEM_TARGET_PCI_NOSNOOP 2
#define NV_MEM_TARGET_VM          3
#define NV_MEM_TARGET_GART        4

#define NV_MEM_TYPE_VM 0x7f
#define NV_MEM_COMP_VM 0x03

/* NV_SW object class */
#define NV_SW                                                        0x0000506e
#define NV_SW_DMA_SEMAPHORE                                          0x00000060
#define NV_SW_SEMAPHORE_OFFSET                                       0x00000064
+2 −2
Original line number Diff line number Diff line
@@ -459,8 +459,8 @@ nouveau_fence_channel_init(struct nouveau_channel *chan)
		ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
					     mem->start << PAGE_SHIFT,
					     mem->size << PAGE_SHIFT,
					     NV_DMA_ACCESS_RW,
					     NV_DMA_TARGET_VIDMEM, &obj);
					     NV_MEM_ACCESS_RW,
					     NV_MEM_TARGET_VRAM, &obj);
		if (ret)
			return ret;

+6 −23
Original line number Diff line number Diff line
@@ -99,7 +99,6 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
		       int size, uint32_t *b_offset)
{
	struct drm_device *dev = chan->dev;
	struct drm_nouveau_private *dev_priv = dev->dev_private;
	struct nouveau_gpuobj *nobj = NULL;
	struct drm_mm_node *mem;
	uint32_t offset;
@@ -113,31 +112,15 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
		return -ENOMEM;
	}

	if (chan->notifier_bo->bo.mem.mem_type == TTM_PL_VRAM)
		target = NV_MEM_TARGET_VRAM;
	else
		target = NV_MEM_TARGET_GART;
	offset  = chan->notifier_bo->bo.mem.start << PAGE_SHIFT;
	if (chan->notifier_bo->bo.mem.mem_type == TTM_PL_VRAM) {
		target = NV_DMA_TARGET_VIDMEM;
	} else
	if (chan->notifier_bo->bo.mem.mem_type == TTM_PL_TT) {
		if (dev_priv->gart_info.type == NOUVEAU_GART_SGDMA &&
		    dev_priv->card_type < NV_50) {
			ret = nouveau_sgdma_get_page(dev, offset, &offset);
			if (ret)
				return ret;
			target = NV_DMA_TARGET_PCI;
		} else {
			target = NV_DMA_TARGET_AGP;
			if (dev_priv->card_type >= NV_50)
				offset += dev_priv->vm_gart_base;
		}
	} else {
		NV_ERROR(dev, "Bad DMA target, mem_type %d!\n",
			 chan->notifier_bo->bo.mem.mem_type);
		return -EINVAL;
	}
	offset += mem->start;

	ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, offset,
				     mem->size, NV_DMA_ACCESS_RW, target,
				     mem->size, NV_MEM_ACCESS_RW, target,
				     &nobj);
	if (ret) {
		drm_mm_put_block(mem);
+136 −99
Original line number Diff line number Diff line
@@ -404,113 +404,157 @@ nouveau_gpuobj_class_instmem_size(struct drm_device *dev, int class)
   The method below creates a DMA object in instance RAM and returns a handle
   to it that can be used to set up context objects.
*/
int
nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class,
		       uint64_t offset, uint64_t size, int access,
		       int target, struct nouveau_gpuobj **gpuobj)

void
nv50_gpuobj_dma_init(struct nouveau_gpuobj *obj, u32 offset, int class,
		     u64 base, u64 size, int target, int access,
		     u32 type, u32 comp)
{
	struct drm_device *dev = chan->dev;
	struct drm_nouveau_private *dev_priv = dev->dev_private;
	struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem;
	int ret;
	struct drm_nouveau_private *dev_priv = obj->dev->dev_private;
	struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
	u32 flags0;

	NV_DEBUG(dev, "ch%d class=0x%04x offset=0x%llx size=0x%llx\n",
		 chan->id, class, offset, size);
	NV_DEBUG(dev, "access=%d target=%d\n", access, target);
	flags0  = (comp << 29) | (type << 22) | class;
	flags0 |= 0x00100000;

	switch (access) {
	case NV_MEM_ACCESS_RO: flags0 |= 0x00040000; break;
	case NV_MEM_ACCESS_RW:
	case NV_MEM_ACCESS_WO: flags0 |= 0x00080000; break;
	default:
		break;
	}

	switch (target) {
	case NV_DMA_TARGET_AGP:
		offset += dev_priv->gart_info.aper_base;
	case NV_MEM_TARGET_VRAM:
		flags0 |= 0x00010000;
		break;
	case NV_MEM_TARGET_PCI:
		flags0 |= 0x00020000;
		break;
	case NV_MEM_TARGET_PCI_NOSNOOP:
		flags0 |= 0x00030000;
		break;
	case NV_MEM_TARGET_GART:
		base += dev_priv->vm_gart_base;
	default:
		flags0 &= ~0x00100000;
		break;
	}

	ret = nouveau_gpuobj_new(dev, chan,
				 nouveau_gpuobj_class_instmem_size(dev, class),
				 16, NVOBJ_FLAG_ZERO_ALLOC |
				 NVOBJ_FLAG_ZERO_FREE, gpuobj);
	if (ret) {
		NV_ERROR(dev, "Error creating gpuobj: %d\n", ret);
		return ret;
	}
	/* convert to base + limit */
	size = (base + size) - 1;

	if (dev_priv->card_type < NV_50) {
		uint32_t frame, adjust, pte_flags = 0;

		if (access != NV_DMA_ACCESS_RO)
			pte_flags |= (1<<1);
		adjust = offset &  0x00000fff;
		frame  = offset & ~0x00000fff;

		nv_wo32(*gpuobj,  0, ((1<<12) | (1<<13) | (adjust << 20) |
				      (access << 14) | (target << 16) |
				      class));
		nv_wo32(*gpuobj,  4, size - 1);
		nv_wo32(*gpuobj,  8, frame | pte_flags);
		nv_wo32(*gpuobj, 12, frame | pte_flags);
	} else {
		uint64_t limit = offset + size - 1;
		uint32_t flags0, flags5;
	nv_wo32(obj, offset + 0x00, flags0);
	nv_wo32(obj, offset + 0x04, lower_32_bits(size));
	nv_wo32(obj, offset + 0x08, lower_32_bits(base));
	nv_wo32(obj, offset + 0x0c, upper_32_bits(size) << 24 |
				    upper_32_bits(base));
	nv_wo32(obj, offset + 0x10, 0x00000000);
	nv_wo32(obj, offset + 0x14, 0x00000000);

		if (target == NV_DMA_TARGET_VIDMEM) {
			flags0 = 0x00190000;
			flags5 = 0x00010000;
		} else {
			flags0 = 0x7fc00000;
			flags5 = 0x00080000;
	pinstmem->flush(obj->dev);
}

		nv_wo32(*gpuobj,  0, flags0 | class);
		nv_wo32(*gpuobj,  4, lower_32_bits(limit));
		nv_wo32(*gpuobj,  8, lower_32_bits(offset));
		nv_wo32(*gpuobj, 12, ((upper_32_bits(limit) & 0xff) << 24) |
				      (upper_32_bits(offset) & 0xff));
		nv_wo32(*gpuobj, 20, flags5);
	}
int
nv50_gpuobj_dma_new(struct nouveau_channel *chan, int class, u64 base, u64 size,
		    int target, int access, u32 type, u32 comp,
		    struct nouveau_gpuobj **pobj)
{
	struct drm_device *dev = chan->dev;
	int ret;

	instmem->flush(dev);
	ret = nouveau_gpuobj_new(dev, chan, 24, 16, NVOBJ_FLAG_ZERO_ALLOC |
				 NVOBJ_FLAG_ZERO_FREE, pobj);
	if (ret)
		return ret;

	(*gpuobj)->engine = NVOBJ_ENGINE_SW;
	(*gpuobj)->class  = class;
	nv50_gpuobj_dma_init(*pobj, 0, class, base, size, target,
			     access, type, comp);
	return 0;
}

int
nouveau_gpuobj_gart_dma_new(struct nouveau_channel *chan,
			    uint64_t offset, uint64_t size, int access,
			    struct nouveau_gpuobj **gpuobj,
			    uint32_t *o_ret)
nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class, u64 base,
		       u64 size, int access, int target,
		       struct nouveau_gpuobj **pobj)
{
	struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
	struct drm_device *dev = chan->dev;
	struct drm_nouveau_private *dev_priv = dev->dev_private;
	struct nouveau_gpuobj *obj;
	u32 page_addr, flags0, flags2;
	int ret;

	if (dev_priv->gart_info.type == NOUVEAU_GART_AGP ||
	    (dev_priv->card_type >= NV_50 &&
	     dev_priv->gart_info.type == NOUVEAU_GART_SGDMA)) {
		ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
					     offset + dev_priv->vm_gart_base,
					     size, access, NV_DMA_TARGET_AGP,
					     gpuobj);
		if (o_ret)
			*o_ret = 0;
	} else
	if (dev_priv->gart_info.type == NOUVEAU_GART_SGDMA) {
		nouveau_gpuobj_ref(dev_priv->gart_info.sg_ctxdma, gpuobj);
		if (offset & ~0xffffffffULL) {
			NV_ERROR(dev, "obj offset exceeds 32-bits\n");
			return -EINVAL;
	if (dev_priv->card_type >= NV_50) {
		u32 comp = (target == NV_MEM_TARGET_VM) ? NV_MEM_COMP_VM : 0;
		u32 type = (target == NV_MEM_TARGET_VM) ? NV_MEM_TYPE_VM : 0;

		return nv50_gpuobj_dma_new(chan, class, base, size,
					   target, access, type, comp, pobj);
	}
		if (o_ret)
			*o_ret = (uint32_t)offset;
		ret = (*gpuobj != NULL) ? 0 : -EINVAL;

	if (target == NV_MEM_TARGET_GART) {
		if (dev_priv->gart_info.type == NOUVEAU_GART_AGP) {
			target = NV_MEM_TARGET_PCI_NOSNOOP;
			base  += dev_priv->gart_info.aper_base;
		} else
		if (base != 0) {
			ret = nouveau_sgdma_get_page(dev, base, &page_addr);
			if (ret)
				return ret;

			target = NV_MEM_TARGET_PCI;
			base   = page_addr;
		} else {
		NV_ERROR(dev, "Invalid GART type %d\n", dev_priv->gart_info.type);
		return -EINVAL;
			nouveau_gpuobj_ref(dev_priv->gart_info.sg_ctxdma, pobj);
			return 0;
		}
	}

	flags0  = class;
	flags0 |= 0x00003000; /* PT present, PT linear */
	flags2  = 0;

	switch (target) {
	case NV_MEM_TARGET_PCI:
		flags0 |= 0x00020000;
		break;
	case NV_MEM_TARGET_PCI_NOSNOOP:
		flags0 |= 0x00030000;
		break;
	default:
		break;
	}

	switch (access) {
	case NV_MEM_ACCESS_RO:
		flags0 |= 0x00004000;
		break;
	case NV_MEM_ACCESS_WO:
		flags0 |= 0x00008000;
	default:
		flags2 |= 0x00000002;
		break;
	}

	flags0 |= (base & 0x00000fff) << 20;
	flags2 |= (base & 0xfffff000);

	ret = nouveau_gpuobj_new(dev, chan, (dev_priv->card_type >= NV_40) ?
				 32 : 16, 16, NVOBJ_FLAG_ZERO_ALLOC |
				 NVOBJ_FLAG_ZERO_FREE, &obj);
	if (ret)
		return ret;

	nv_wo32(obj, 0x00, flags0);
	nv_wo32(obj, 0x04, size - 1);
	nv_wo32(obj, 0x08, flags2);
	nv_wo32(obj, 0x0c, flags2);

	obj->engine = NVOBJ_ENGINE_SW;
	obj->class  = class;
	*pobj = obj;
	return 0;
}

/* Context objects in the instance RAM have the following structure.
@@ -806,8 +850,8 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
	if (dev_priv->card_type >= NV_50) {
		ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
					     0, dev_priv->vm_end,
					     NV_DMA_ACCESS_RW,
					     NV_DMA_TARGET_AGP, &vram);
					     NV_MEM_ACCESS_RW,
					     NV_MEM_TARGET_VM, &vram);
		if (ret) {
			NV_ERROR(dev, "Error creating VRAM ctxdma: %d\n", ret);
			return ret;
@@ -815,8 +859,8 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
	} else {
		ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
					     0, dev_priv->fb_available_size,
					     NV_DMA_ACCESS_RW,
					     NV_DMA_TARGET_VIDMEM, &vram);
					     NV_MEM_ACCESS_RW,
					     NV_MEM_TARGET_VRAM, &vram);
		if (ret) {
			NV_ERROR(dev, "Error creating VRAM ctxdma: %d\n", ret);
			return ret;
@@ -834,20 +878,13 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
	if (dev_priv->card_type >= NV_50) {
		ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
					     0, dev_priv->vm_end,
					     NV_DMA_ACCESS_RW,
					     NV_DMA_TARGET_AGP, &tt);
		if (ret) {
			NV_ERROR(dev, "Error creating VRAM ctxdma: %d\n", ret);
			return ret;
		}
	} else
	if (dev_priv->gart_info.type != NOUVEAU_GART_NONE) {
		ret = nouveau_gpuobj_gart_dma_new(chan, 0,
						  dev_priv->gart_info.aper_size,
						  NV_DMA_ACCESS_RW, &tt, NULL);
					     NV_MEM_ACCESS_RW,
					     NV_MEM_TARGET_VM, &tt);
	} else {
		NV_ERROR(dev, "Invalid GART type %d\n", dev_priv->gart_info.type);
		ret = -EINVAL;
		ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
					     0, dev_priv->gart_info.aper_size,
					     NV_MEM_ACCESS_RW,
					     NV_MEM_TARGET_GART, &tt);
	}

	if (ret) {
Loading