162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright 2017 Red Hat Inc. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 562306a36Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 662306a36Sopenharmony_ci * to deal in the Software without restriction, including without limitation 762306a36Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 862306a36Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 962306a36Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 1262306a36Sopenharmony_ci * all copies or substantial portions of the Software. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1562306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1662306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1762306a36Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 1862306a36Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 1962306a36Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 2062306a36Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 2162306a36Sopenharmony_ci */ 2262306a36Sopenharmony_ci#include <nvif/mmu.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include <nvif/class.h> 2562306a36Sopenharmony_ci#include <nvif/if0008.h> 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_civoid 2862306a36Sopenharmony_cinvif_mmu_dtor(struct nvif_mmu *mmu) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci if (!nvif_object_constructed(&mmu->object)) 3162306a36Sopenharmony_ci return; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci kfree(mmu->kind); 3462306a36Sopenharmony_ci kfree(mmu->type); 3562306a36Sopenharmony_ci kfree(mmu->heap); 3662306a36Sopenharmony_ci nvif_object_dtor(&mmu->object); 3762306a36Sopenharmony_ci} 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ciint 4062306a36Sopenharmony_cinvif_mmu_ctor(struct nvif_object *parent, const char *name, s32 oclass, 4162306a36Sopenharmony_ci struct nvif_mmu *mmu) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci static const struct nvif_mclass mems[] = { 4462306a36Sopenharmony_ci { NVIF_CLASS_MEM_GF100, -1 }, 4562306a36Sopenharmony_ci { NVIF_CLASS_MEM_NV50 , -1 }, 4662306a36Sopenharmony_ci { NVIF_CLASS_MEM_NV04 , -1 }, 4762306a36Sopenharmony_ci {} 4862306a36Sopenharmony_ci }; 4962306a36Sopenharmony_ci struct nvif_mmu_v0 args; 5062306a36Sopenharmony_ci int ret, i; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci args.version = 0; 5362306a36Sopenharmony_ci mmu->heap = NULL; 5462306a36Sopenharmony_ci mmu->type = NULL; 5562306a36Sopenharmony_ci mmu->kind = NULL; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci ret = nvif_object_ctor(parent, name ? name : "nvifMmu", 0, oclass, 5862306a36Sopenharmony_ci &args, sizeof(args), &mmu->object); 5962306a36Sopenharmony_ci if (ret) 6062306a36Sopenharmony_ci goto done; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci mmu->dmabits = args.dmabits; 6362306a36Sopenharmony_ci mmu->heap_nr = args.heap_nr; 6462306a36Sopenharmony_ci mmu->type_nr = args.type_nr; 6562306a36Sopenharmony_ci mmu->kind_nr = args.kind_nr; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci ret = nvif_mclass(&mmu->object, mems); 6862306a36Sopenharmony_ci if (ret < 0) 6962306a36Sopenharmony_ci goto done; 7062306a36Sopenharmony_ci mmu->mem = mems[ret].oclass; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci mmu->heap = kmalloc_array(mmu->heap_nr, sizeof(*mmu->heap), 7362306a36Sopenharmony_ci GFP_KERNEL); 7462306a36Sopenharmony_ci mmu->type = kmalloc_array(mmu->type_nr, sizeof(*mmu->type), 7562306a36Sopenharmony_ci GFP_KERNEL); 7662306a36Sopenharmony_ci if (ret = -ENOMEM, !mmu->heap || !mmu->type) 7762306a36Sopenharmony_ci goto done; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci mmu->kind = kmalloc_array(mmu->kind_nr, sizeof(*mmu->kind), 8062306a36Sopenharmony_ci GFP_KERNEL); 8162306a36Sopenharmony_ci if (!mmu->kind && mmu->kind_nr) 8262306a36Sopenharmony_ci goto done; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci for (i = 0; i < mmu->heap_nr; i++) { 8562306a36Sopenharmony_ci struct nvif_mmu_heap_v0 args = { .index = i }; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci ret = nvif_object_mthd(&mmu->object, NVIF_MMU_V0_HEAP, 8862306a36Sopenharmony_ci &args, sizeof(args)); 8962306a36Sopenharmony_ci if (ret) 9062306a36Sopenharmony_ci goto done; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci mmu->heap[i].size = args.size; 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci for (i = 0; i < mmu->type_nr; i++) { 9662306a36Sopenharmony_ci struct nvif_mmu_type_v0 args = { .index = i }; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci ret = nvif_object_mthd(&mmu->object, NVIF_MMU_V0_TYPE, 9962306a36Sopenharmony_ci &args, sizeof(args)); 10062306a36Sopenharmony_ci if (ret) 10162306a36Sopenharmony_ci goto done; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci mmu->type[i].type = 0; 10462306a36Sopenharmony_ci if (args.vram) mmu->type[i].type |= NVIF_MEM_VRAM; 10562306a36Sopenharmony_ci if (args.host) mmu->type[i].type |= NVIF_MEM_HOST; 10662306a36Sopenharmony_ci if (args.comp) mmu->type[i].type |= NVIF_MEM_COMP; 10762306a36Sopenharmony_ci if (args.disp) mmu->type[i].type |= NVIF_MEM_DISP; 10862306a36Sopenharmony_ci if (args.kind ) mmu->type[i].type |= NVIF_MEM_KIND; 10962306a36Sopenharmony_ci if (args.mappable) mmu->type[i].type |= NVIF_MEM_MAPPABLE; 11062306a36Sopenharmony_ci if (args.coherent) mmu->type[i].type |= NVIF_MEM_COHERENT; 11162306a36Sopenharmony_ci if (args.uncached) mmu->type[i].type |= NVIF_MEM_UNCACHED; 11262306a36Sopenharmony_ci mmu->type[i].heap = args.heap; 11362306a36Sopenharmony_ci } 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci if (mmu->kind_nr) { 11662306a36Sopenharmony_ci struct nvif_mmu_kind_v0 *kind; 11762306a36Sopenharmony_ci size_t argc = struct_size(kind, data, mmu->kind_nr); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci if (ret = -ENOMEM, !(kind = kmalloc(argc, GFP_KERNEL))) 12062306a36Sopenharmony_ci goto done; 12162306a36Sopenharmony_ci kind->version = 0; 12262306a36Sopenharmony_ci kind->count = mmu->kind_nr; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci ret = nvif_object_mthd(&mmu->object, NVIF_MMU_V0_KIND, 12562306a36Sopenharmony_ci kind, argc); 12662306a36Sopenharmony_ci if (ret == 0) 12762306a36Sopenharmony_ci memcpy(mmu->kind, kind->data, kind->count); 12862306a36Sopenharmony_ci mmu->kind_inv = kind->kind_inv; 12962306a36Sopenharmony_ci kfree(kind); 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cidone: 13362306a36Sopenharmony_ci if (ret) 13462306a36Sopenharmony_ci nvif_mmu_dtor(mmu); 13562306a36Sopenharmony_ci return ret; 13662306a36Sopenharmony_ci} 137