18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright 2017 Red Hat Inc.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
58c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
68c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation
78c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
88c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
98c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice shall be included in
128c2ecf20Sopenharmony_ci * all copies or substantial portions of the Software.
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
158c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
168c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
178c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
188c2ecf20Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
198c2ecf20Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
208c2ecf20Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
218c2ecf20Sopenharmony_ci */
228c2ecf20Sopenharmony_ci#include <nvif/vmm.h>
238c2ecf20Sopenharmony_ci#include <nvif/mem.h>
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#include <nvif/if000c.h>
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ciint
288c2ecf20Sopenharmony_cinvif_vmm_unmap(struct nvif_vmm *vmm, u64 addr)
298c2ecf20Sopenharmony_ci{
308c2ecf20Sopenharmony_ci	return nvif_object_mthd(&vmm->object, NVIF_VMM_V0_UNMAP,
318c2ecf20Sopenharmony_ci				&(struct nvif_vmm_unmap_v0) { .addr = addr },
328c2ecf20Sopenharmony_ci				sizeof(struct nvif_vmm_unmap_v0));
338c2ecf20Sopenharmony_ci}
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ciint
368c2ecf20Sopenharmony_cinvif_vmm_map(struct nvif_vmm *vmm, u64 addr, u64 size, void *argv, u32 argc,
378c2ecf20Sopenharmony_ci	     struct nvif_mem *mem, u64 offset)
388c2ecf20Sopenharmony_ci{
398c2ecf20Sopenharmony_ci	struct nvif_vmm_map_v0 *args;
408c2ecf20Sopenharmony_ci	u8 stack[48];
418c2ecf20Sopenharmony_ci	int ret;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	if (sizeof(*args) + argc > sizeof(stack)) {
448c2ecf20Sopenharmony_ci		if (!(args = kmalloc(sizeof(*args) + argc, GFP_KERNEL)))
458c2ecf20Sopenharmony_ci			return -ENOMEM;
468c2ecf20Sopenharmony_ci	} else {
478c2ecf20Sopenharmony_ci		args = (void *)stack;
488c2ecf20Sopenharmony_ci	}
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	args->version = 0;
518c2ecf20Sopenharmony_ci	args->addr = addr;
528c2ecf20Sopenharmony_ci	args->size = size;
538c2ecf20Sopenharmony_ci	args->memory = nvif_handle(&mem->object);
548c2ecf20Sopenharmony_ci	args->offset = offset;
558c2ecf20Sopenharmony_ci	memcpy(args->data, argv, argc);
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	ret = nvif_object_mthd(&vmm->object, NVIF_VMM_V0_MAP,
588c2ecf20Sopenharmony_ci			       args, sizeof(*args) + argc);
598c2ecf20Sopenharmony_ci	if (args != (void *)stack)
608c2ecf20Sopenharmony_ci		kfree(args);
618c2ecf20Sopenharmony_ci	return ret;
628c2ecf20Sopenharmony_ci}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_civoid
658c2ecf20Sopenharmony_cinvif_vmm_put(struct nvif_vmm *vmm, struct nvif_vma *vma)
668c2ecf20Sopenharmony_ci{
678c2ecf20Sopenharmony_ci	if (vma->size) {
688c2ecf20Sopenharmony_ci		WARN_ON(nvif_object_mthd(&vmm->object, NVIF_VMM_V0_PUT,
698c2ecf20Sopenharmony_ci					 &(struct nvif_vmm_put_v0) {
708c2ecf20Sopenharmony_ci						.addr = vma->addr,
718c2ecf20Sopenharmony_ci					 }, sizeof(struct nvif_vmm_put_v0)));
728c2ecf20Sopenharmony_ci		vma->size = 0;
738c2ecf20Sopenharmony_ci	}
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ciint
778c2ecf20Sopenharmony_cinvif_vmm_get(struct nvif_vmm *vmm, enum nvif_vmm_get type, bool sparse,
788c2ecf20Sopenharmony_ci	     u8 page, u8 align, u64 size, struct nvif_vma *vma)
798c2ecf20Sopenharmony_ci{
808c2ecf20Sopenharmony_ci	struct nvif_vmm_get_v0 args;
818c2ecf20Sopenharmony_ci	int ret;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	args.version = vma->size = 0;
848c2ecf20Sopenharmony_ci	args.sparse = sparse;
858c2ecf20Sopenharmony_ci	args.page = page;
868c2ecf20Sopenharmony_ci	args.align = align;
878c2ecf20Sopenharmony_ci	args.size = size;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	switch (type) {
908c2ecf20Sopenharmony_ci	case ADDR: args.type = NVIF_VMM_GET_V0_ADDR; break;
918c2ecf20Sopenharmony_ci	case PTES: args.type = NVIF_VMM_GET_V0_PTES; break;
928c2ecf20Sopenharmony_ci	case LAZY: args.type = NVIF_VMM_GET_V0_LAZY; break;
938c2ecf20Sopenharmony_ci	default:
948c2ecf20Sopenharmony_ci		WARN_ON(1);
958c2ecf20Sopenharmony_ci		return -EINVAL;
968c2ecf20Sopenharmony_ci	}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	ret = nvif_object_mthd(&vmm->object, NVIF_VMM_V0_GET,
998c2ecf20Sopenharmony_ci			       &args, sizeof(args));
1008c2ecf20Sopenharmony_ci	if (ret == 0) {
1018c2ecf20Sopenharmony_ci		vma->addr = args.addr;
1028c2ecf20Sopenharmony_ci		vma->size = args.size;
1038c2ecf20Sopenharmony_ci	}
1048c2ecf20Sopenharmony_ci	return ret;
1058c2ecf20Sopenharmony_ci}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_civoid
1088c2ecf20Sopenharmony_cinvif_vmm_dtor(struct nvif_vmm *vmm)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	kfree(vmm->page);
1118c2ecf20Sopenharmony_ci	nvif_object_dtor(&vmm->object);
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ciint
1158c2ecf20Sopenharmony_cinvif_vmm_ctor(struct nvif_mmu *mmu, const char *name, s32 oclass, bool managed,
1168c2ecf20Sopenharmony_ci	      u64 addr, u64 size, void *argv, u32 argc, struct nvif_vmm *vmm)
1178c2ecf20Sopenharmony_ci{
1188c2ecf20Sopenharmony_ci	struct nvif_vmm_v0 *args;
1198c2ecf20Sopenharmony_ci	u32 argn = sizeof(*args) + argc;
1208c2ecf20Sopenharmony_ci	int ret = -ENOSYS, i;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	vmm->object.client = NULL;
1238c2ecf20Sopenharmony_ci	vmm->page = NULL;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	if (!(args = kmalloc(argn, GFP_KERNEL)))
1268c2ecf20Sopenharmony_ci		return -ENOMEM;
1278c2ecf20Sopenharmony_ci	args->version = 0;
1288c2ecf20Sopenharmony_ci	args->managed = managed;
1298c2ecf20Sopenharmony_ci	args->addr = addr;
1308c2ecf20Sopenharmony_ci	args->size = size;
1318c2ecf20Sopenharmony_ci	memcpy(args->data, argv, argc);
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	ret = nvif_object_ctor(&mmu->object, name ? name : "nvifVmm", 0,
1348c2ecf20Sopenharmony_ci			       oclass, args, argn, &vmm->object);
1358c2ecf20Sopenharmony_ci	if (ret)
1368c2ecf20Sopenharmony_ci		goto done;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	vmm->start = args->addr;
1398c2ecf20Sopenharmony_ci	vmm->limit = args->size;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	vmm->page_nr = args->page_nr;
1428c2ecf20Sopenharmony_ci	vmm->page = kmalloc_array(vmm->page_nr, sizeof(*vmm->page),
1438c2ecf20Sopenharmony_ci				  GFP_KERNEL);
1448c2ecf20Sopenharmony_ci	if (!vmm->page) {
1458c2ecf20Sopenharmony_ci		ret = -ENOMEM;
1468c2ecf20Sopenharmony_ci		goto done;
1478c2ecf20Sopenharmony_ci	}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	for (i = 0; i < vmm->page_nr; i++) {
1508c2ecf20Sopenharmony_ci		struct nvif_vmm_page_v0 args = { .index = i };
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci		ret = nvif_object_mthd(&vmm->object, NVIF_VMM_V0_PAGE,
1538c2ecf20Sopenharmony_ci				       &args, sizeof(args));
1548c2ecf20Sopenharmony_ci		if (ret)
1558c2ecf20Sopenharmony_ci			break;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci		vmm->page[i].shift = args.shift;
1588c2ecf20Sopenharmony_ci		vmm->page[i].sparse = args.sparse;
1598c2ecf20Sopenharmony_ci		vmm->page[i].vram = args.vram;
1608c2ecf20Sopenharmony_ci		vmm->page[i].host = args.host;
1618c2ecf20Sopenharmony_ci		vmm->page[i].comp = args.comp;
1628c2ecf20Sopenharmony_ci	}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_cidone:
1658c2ecf20Sopenharmony_ci	if (ret)
1668c2ecf20Sopenharmony_ci		nvif_vmm_dtor(vmm);
1678c2ecf20Sopenharmony_ci	kfree(args);
1688c2ecf20Sopenharmony_ci	return ret;
1698c2ecf20Sopenharmony_ci}
170