static int
gk20a_ram_get(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin,
	     u32 memtype, struct nouveau_mem **pmem)
{
#if !defined(__NetBSD__)
	struct device *dev = nv_device_base(nv_device(pfb));
	int i;
#endif
	struct gk20a_mem *mem;
	u32 type = memtype & 0xff;
	u32 npages, order;

	nv_debug(pfb, "%s: size: %llx align: %x, ncmin: %x\n", __func__,
		 (unsigned long long)size, align, ncmin);

	npages = size >> PAGE_SHIFT;
	if (npages == 0)
		npages = 1;

	if (align == 0)
		align = PAGE_SIZE;
	align >>= PAGE_SHIFT;

	/* round alignment to the next power of 2, if needed */
#if defined(__NetBSD__)
	order = fls32(align);
#else
	order = fls(align);
#endif
	if ((align & (align - 1)) == 0)
		order--;
	align = BIT(order);

	/* ensure returned address is correctly aligned */
	npages = max(align, npages);

	mem = kzalloc(sizeof(*mem), GFP_KERNEL);
	if (!mem)
		return -ENOMEM;

	mem->base.size = npages;
	mem->base.memtype = type;

#if defined(__NetBSD__)
	int ret, nsegs;

	if (align == 0)
		align = PAGE_SIZE;

	const bus_dma_tag_t dmat = nv_device(pfb)->platformdev->dmat;
	const bus_size_t dmasize = npages << PAGE_SHIFT;

	ret = -bus_dmamem_alloc(dmat, dmasize, align, 0,
	    &mem->dmaseg, 1, &nsegs, BUS_DMA_WAITOK);
	if (ret) {
fail0:		kfree(mem);
		return ret;
	}
	KASSERT(nsegs == 1);

	ret = -bus_dmamap_create(dmat, dmasize, nsegs, dmasize, 0,
	    BUS_DMA_WAITOK, &mem->base.pages);
	if (ret) {
fail1:		bus_dmamem_free(dmat, &mem->dmaseg, nsegs);
		goto fail0;
	}

	ret = -bus_dmamem_map(dmat, &mem->dmaseg, nsegs, dmasize,
	    &mem->cpuaddr, BUS_DMA_WAITOK | BUS_DMA_COHERENT);
	if (ret) {
fail2:		bus_dmamap_destroy(dmat, mem->base.pages);
		goto fail1;
	}
	memset(mem->cpuaddr, 0, dmasize);

	ret = -bus_dmamap_load(dmat, mem->base.pages, mem->cpuaddr,
	    dmasize, NULL, BUS_DMA_WAITOK);
	if (ret) {
fail3: __unused	bus_dmamem_unmap(dmat, mem->cpuaddr, dmasize);
		goto fail2;
	}

	nv_debug(pfb, "alloc size: 0x%x, align: 0x%x, paddr: %"PRIxPADDR
	   ", vaddr: %p\n", npages << PAGE_SHIFT, align,
	   mem->base.pages->dm_segs[0].ds_addr, mem->cpuaddr);

	mem->dmasize = dmasize;
	mem->base.offset = (u64)mem->base.pages->dm_segs[0].ds_addr;
	*pmem = &mem->base;
#else
	mem->base.pages = kzalloc(sizeof(dma_addr_t) * npages, GFP_KERNEL);
	if (!mem->base.pages) {
		kfree(mem);
		return -ENOMEM;
	}

	*pmem = &mem->base;

	mem->cpuaddr = dma_alloc_coherent(dev, npages << PAGE_SHIFT,
					  &mem->handle, GFP_KERNEL);
	if (!mem->cpuaddr) {
		nv_error(pfb, "%s: cannot allocate memory!\n", __func__);
		gk20a_ram_put(pfb, pmem);
		return -ENOMEM;
	}

	align <<= PAGE_SHIFT;

	/* alignment check */
	if (unlikely(mem->handle & (align - 1)))
		nv_warn(pfb, "memory not aligned as requested: %pad (0x%x)\n",
			&mem->handle, align);

	nv_debug(pfb, "alloc size: 0x%x, align: 0x%x, paddr: %pad, vaddr: %p\n",
		 npages << PAGE_SHIFT, align, &mem->handle, mem->cpuaddr);

	for (i = 0; i < npages; i++)
		mem->base.pages[i] = mem->handle + (PAGE_SIZE * i);

	mem->base.offset = (u64)mem->base.pages[0];
#endif

	return 0;
}
Example #2
0
static int
gk20a_ram_get(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin,
	     u32 memtype, struct nouveau_mem **pmem)
{
	struct device *dev = nv_device_base(nv_device(pfb));
	struct gk20a_mem *mem;
	u32 type = memtype & 0xff;
	u32 npages, order;
	int i;

	nv_debug(pfb, "%s: size: %llx align: %x, ncmin: %x\n", __func__, size,
		 align, ncmin);

	npages = size >> PAGE_SHIFT;
	if (npages == 0)
		npages = 1;

	if (align == 0)
		align = PAGE_SIZE;
	align >>= PAGE_SHIFT;

	/* round alignment to the next power of 2, if needed */
	order = fls(align);
	if ((align & (align - 1)) == 0)
		order--;
	align = BIT(order);

	/* ensure returned address is correctly aligned */
	npages = max(align, npages);

	mem = kzalloc(sizeof(*mem), GFP_KERNEL);
	if (!mem)
		return -ENOMEM;

	mem->base.size = npages;
	mem->base.memtype = type;

	mem->base.pages = kzalloc(sizeof(dma_addr_t) * npages, GFP_KERNEL);
	if (!mem->base.pages) {
		kfree(mem);
		return -ENOMEM;
	}

	*pmem = &mem->base;

	mem->cpuaddr = dma_alloc_coherent(dev, npages << PAGE_SHIFT,
					  &mem->handle, GFP_KERNEL);
	if (!mem->cpuaddr) {
		nv_error(pfb, "%s: cannot allocate memory!\n", __func__);
		gk20a_ram_put(pfb, pmem);
		return -ENOMEM;
	}

	align <<= PAGE_SHIFT;

	/* alignment check */
	if (unlikely(mem->handle & (align - 1)))
		nv_warn(pfb, "memory not aligned as requested: %pad (0x%x)\n",
			&mem->handle, align);

	nv_debug(pfb, "alloc size: 0x%x, align: 0x%x, paddr: %pad, vaddr: %p\n",
		 npages << PAGE_SHIFT, align, &mem->handle, mem->cpuaddr);

	for (i = 0; i < npages; i++)
		mem->base.pages[i] = mem->handle + (PAGE_SIZE * i);

	mem->base.offset = (u64)mem->base.pages[0];

	return 0;
}