nouveau_sgdma.c 7.3 KB
Newer Older
1 2 3
#include "drmP.h"
#include "nouveau_drv.h"
#include <linux/pagemap.h>
4
#include <linux/slab.h>
5 6 7 8 9 10 11 12 13 14

#define NV_CTXDMA_PAGE_SHIFT 12
#define NV_CTXDMA_PAGE_SIZE  (1 << NV_CTXDMA_PAGE_SHIFT)
#define NV_CTXDMA_PAGE_MASK  (NV_CTXDMA_PAGE_SIZE - 1)

struct nouveau_sgdma_be {
	struct ttm_backend backend;
	struct drm_device *dev;

	dma_addr_t *pages;
15
	bool *ttm_alloced;
16 17
	unsigned nr_pages;

18
	u64 offset;
19 20 21 22 23
	bool bound;
};

static int
nouveau_sgdma_populate(struct ttm_backend *be, unsigned long num_pages,
24 25
		       struct page **pages, struct page *dummy_read_page,
		       dma_addr_t *dma_addrs)
26 27 28 29 30 31 32 33 34 35 36 37 38
{
	struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be;
	struct drm_device *dev = nvbe->dev;

	NV_DEBUG(nvbe->dev, "num_pages = %ld\n", num_pages);

	if (nvbe->pages)
		return -EINVAL;

	nvbe->pages = kmalloc(sizeof(dma_addr_t) * num_pages, GFP_KERNEL);
	if (!nvbe->pages)
		return -ENOMEM;

39 40 41 42
	nvbe->ttm_alloced = kmalloc(sizeof(bool) * num_pages, GFP_KERNEL);
	if (!nvbe->ttm_alloced)
		return -ENOMEM;

43 44
	nvbe->nr_pages = 0;
	while (num_pages--) {
45 46 47 48 49 50 51
		if (dma_addrs[nvbe->nr_pages] != DMA_ERROR_CODE) {
			nvbe->pages[nvbe->nr_pages] =
					dma_addrs[nvbe->nr_pages];
		 	nvbe->ttm_alloced[nvbe->nr_pages] = true;
		} else {
			nvbe->pages[nvbe->nr_pages] =
				pci_map_page(dev->pdev, pages[nvbe->nr_pages], 0,
52
				     PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
53 54 55 56 57
			if (pci_dma_mapping_error(dev->pdev,
						  nvbe->pages[nvbe->nr_pages])) {
				be->func->clear(be);
				return -EFAULT;
			}
58 59 60 61 62 63 64 65 66 67 68 69
		}

		nvbe->nr_pages++;
	}

	return 0;
}

static void
nouveau_sgdma_clear(struct ttm_backend *be)
{
	struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be;
70
	struct drm_device *dev;
71 72

	if (nvbe && nvbe->pages) {
73 74 75
		dev = nvbe->dev;
		NV_DEBUG(dev, "\n");

76 77 78 79
		if (nvbe->bound)
			be->func->unbind(be);

		while (nvbe->nr_pages--) {
80 81
			if (!nvbe->ttm_alloced[nvbe->nr_pages])
				pci_unmap_page(dev->pdev, nvbe->pages[nvbe->nr_pages],
82 83 84
				       PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
		}
		kfree(nvbe->pages);
85
		kfree(nvbe->ttm_alloced);
86
		nvbe->pages = NULL;
87
		nvbe->ttm_alloced = NULL;
88 89 90 91 92 93 94 95 96 97 98 99 100
		nvbe->nr_pages = 0;
	}
}

static int
nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem)
{
	struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be;
	struct drm_device *dev = nvbe->dev;
	struct drm_nouveau_private *dev_priv = dev->dev_private;
	struct nouveau_gpuobj *gpuobj = dev_priv->gart_info.sg_ctxdma;
	unsigned i, j, pte;

101
	NV_DEBUG(dev, "pg=0x%lx\n", mem->start);
102

103 104
	nvbe->offset = mem->start << PAGE_SHIFT;
	pte = (nvbe->offset >> NV_CTXDMA_PAGE_SHIFT) + 2;
105 106 107 108
	for (i = 0; i < nvbe->nr_pages; i++) {
		dma_addr_t dma_offset = nvbe->pages[i];
		uint32_t offset_l = lower_32_bits(dma_offset);

109 110
		for (j = 0; j < PAGE_SIZE / NV_CTXDMA_PAGE_SIZE; j++, pte++) {
			nv_wo32(gpuobj, (pte * 4) + 0, offset_l | 3);
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
			dma_offset += NV_CTXDMA_PAGE_SIZE;
		}
	}

	nvbe->bound = true;
	return 0;
}

static int
nouveau_sgdma_unbind(struct ttm_backend *be)
{
	struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be;
	struct drm_device *dev = nvbe->dev;
	struct drm_nouveau_private *dev_priv = dev->dev_private;
	struct nouveau_gpuobj *gpuobj = dev_priv->gart_info.sg_ctxdma;
	unsigned i, j, pte;

	NV_DEBUG(dev, "\n");

	if (!nvbe->bound)
		return 0;

133
	pte = (nvbe->offset >> NV_CTXDMA_PAGE_SHIFT) + 2;
134
	for (i = 0; i < nvbe->nr_pages; i++) {
135 136
		for (j = 0; j < PAGE_SIZE / NV_CTXDMA_PAGE_SIZE; j++, pte++)
			nv_wo32(gpuobj, (pte * 4) + 0, 0x00000000);
137 138
	}

139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
	nvbe->bound = false;
	return 0;
}

static void
nouveau_sgdma_destroy(struct ttm_backend *be)
{
	struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be;

	if (be) {
		NV_DEBUG(nvbe->dev, "\n");

		if (nvbe) {
			if (nvbe->pages)
				be->func->clear(be);
			kfree(nvbe);
		}
	}
}

159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
static int
nv50_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem)
{
	struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be;
	struct drm_nouveau_private *dev_priv = nvbe->dev->dev_private;

	nvbe->offset = mem->start << PAGE_SHIFT;

	nouveau_vm_map_sg(&dev_priv->gart_info.vma, nvbe->offset,
			  nvbe->nr_pages << PAGE_SHIFT, nvbe->pages);
	nvbe->bound = true;
	return 0;
}

static int
nv50_sgdma_unbind(struct ttm_backend *be)
{
	struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be;
	struct drm_nouveau_private *dev_priv = nvbe->dev->dev_private;

	if (!nvbe->bound)
		return 0;

	nouveau_vm_unmap_at(&dev_priv->gart_info.vma, nvbe->offset,
			    nvbe->nr_pages << PAGE_SHIFT);
	nvbe->bound = false;
	return 0;
}

188 189 190 191 192 193 194 195
static struct ttm_backend_func nouveau_sgdma_backend = {
	.populate		= nouveau_sgdma_populate,
	.clear			= nouveau_sgdma_clear,
	.bind			= nouveau_sgdma_bind,
	.unbind			= nouveau_sgdma_unbind,
	.destroy		= nouveau_sgdma_destroy
};

196 197 198 199 200 201 202 203
static struct ttm_backend_func nv50_sgdma_backend = {
	.populate		= nouveau_sgdma_populate,
	.clear			= nouveau_sgdma_clear,
	.bind			= nv50_sgdma_bind,
	.unbind			= nv50_sgdma_unbind,
	.destroy		= nouveau_sgdma_destroy
};

204 205 206 207 208 209 210 211 212 213 214 215
struct ttm_backend *
nouveau_sgdma_init_ttm(struct drm_device *dev)
{
	struct drm_nouveau_private *dev_priv = dev->dev_private;
	struct nouveau_sgdma_be *nvbe;

	nvbe = kzalloc(sizeof(*nvbe), GFP_KERNEL);
	if (!nvbe)
		return NULL;

	nvbe->dev = dev;

216 217 218 219
	if (dev_priv->card_type < NV_50)
		nvbe->backend.func = &nouveau_sgdma_backend;
	else
		nvbe->backend.func = &nv50_sgdma_backend;
220 221 222 223 224 225 226 227 228 229 230 231
	return &nvbe->backend;
}

int
nouveau_sgdma_init(struct drm_device *dev)
{
	struct drm_nouveau_private *dev_priv = dev->dev_private;
	struct nouveau_gpuobj *gpuobj = NULL;
	uint32_t aper_size, obj_size;
	int i, ret;

	if (dev_priv->card_type < NV_50) {
232 233 234 235 236
		if(dev_priv->ramin_rsvd_vram < 2 * 1024 * 1024)
			aper_size = 64 * 1024 * 1024;
		else
			aper_size = 512 * 1024 * 1024;

237 238 239
		obj_size  = (aper_size >> NV_CTXDMA_PAGE_SHIFT) * 4;
		obj_size += 8; /* ctxdma header */

240 241 242 243 244 245 246
		ret = nouveau_gpuobj_new(dev, NULL, obj_size, 16,
					      NVOBJ_FLAG_ZERO_ALLOC |
					      NVOBJ_FLAG_ZERO_FREE, &gpuobj);
		if (ret) {
			NV_ERROR(dev, "Error creating sgdma object: %d\n", ret);
			return ret;
		}
247

248 249 250
		nv_wo32(gpuobj, 0, NV_CLASS_DMA_IN_MEMORY |
				   (1 << 12) /* PT present */ |
				   (0 << 13) /* PT *not* linear */ |
251 252
				   (0 << 14) /* RW */ |
				   (2 << 16) /* PCI */);
253
		nv_wo32(gpuobj, 4, aper_size - 1);
254 255
		for (i = 2; i < 2 + (aper_size >> 12); i++)
			nv_wo32(gpuobj, i * 4, 0x00000000);
256 257 258 259 260 261 262 263 264 265 266 267 268 269

		dev_priv->gart_info.sg_ctxdma = gpuobj;
		dev_priv->gart_info.aper_base = 0;
		dev_priv->gart_info.aper_size = aper_size;
	} else
	if (dev_priv->chan_vm) {
		ret = nouveau_vm_get(dev_priv->chan_vm, 512 * 1024 * 1024,
				     12, NV_MEM_ACCESS_RW,
				     &dev_priv->gart_info.vma);
		if (ret)
			return ret;

		dev_priv->gart_info.aper_base = dev_priv->gart_info.vma.offset;
		dev_priv->gart_info.aper_size = 512 * 1024 * 1024;
270 271 272 273 274 275 276 277 278 279 280
	}

	dev_priv->gart_info.type      = NOUVEAU_GART_SGDMA;
	return 0;
}

void
nouveau_sgdma_takedown(struct drm_device *dev)
{
	struct drm_nouveau_private *dev_priv = dev->dev_private;

281
	nouveau_gpuobj_ref(NULL, &dev_priv->gart_info.sg_ctxdma);
282
	nouveau_vm_put(&dev_priv->gart_info.vma);
283 284
}

285 286
uint32_t
nouveau_sgdma_get_physical(struct drm_device *dev, uint32_t offset)
287 288 289
{
	struct drm_nouveau_private *dev_priv = dev->dev_private;
	struct nouveau_gpuobj *gpuobj = dev_priv->gart_info.sg_ctxdma;
290
	int pte = (offset >> NV_CTXDMA_PAGE_SHIFT) + 2;
291

292
	BUG_ON(dev_priv->card_type >= NV_50);
293

294 295
	return (nv_ro32(gpuobj, 4 * pte) & ~NV_CTXDMA_PAGE_MASK) |
		(offset & NV_CTXDMA_PAGE_MASK);
296
}