brintos

brintos / linux-shallow public Read only

0
0
Text · 4.6 KiB · afe5dd6 Raw
177 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) 2014-2018 Etnaviv Project4 */5 6#include <linux/bitops.h>7#include <linux/dma-mapping.h>8#include <linux/platform_device.h>9#include <linux/sizes.h>10#include <linux/slab.h>11 12#include "etnaviv_gpu.h"13#include "etnaviv_mmu.h"14#include "state_hi.xml.h"15 16#define PT_SIZE		SZ_2M17#define PT_ENTRIES	(PT_SIZE / sizeof(u32))18 19#define GPU_MEM_START	0x8000000020 21struct etnaviv_iommuv1_context {22	struct etnaviv_iommu_context base;23	u32 *pgtable_cpu;24	dma_addr_t pgtable_dma;25};26 27static struct etnaviv_iommuv1_context *28to_v1_context(struct etnaviv_iommu_context *context)29{30	return container_of(context, struct etnaviv_iommuv1_context, base);31}32 33static void etnaviv_iommuv1_free(struct etnaviv_iommu_context *context)34{35	struct etnaviv_iommuv1_context *v1_context = to_v1_context(context);36 37	drm_mm_takedown(&context->mm);38 39	dma_free_wc(context->global->dev, PT_SIZE, v1_context->pgtable_cpu,40		    v1_context->pgtable_dma);41 42	context->global->v1.shared_context = NULL;43 44	kfree(v1_context);45}46 47static int etnaviv_iommuv1_map(struct etnaviv_iommu_context *context,48			       unsigned long iova, phys_addr_t paddr,49			       size_t size, int prot)50{51	struct etnaviv_iommuv1_context *v1_context = to_v1_context(context);52	unsigned int index = (iova - GPU_MEM_START) / SZ_4K;53 54	if (size != SZ_4K)55		return -EINVAL;56 57	v1_context->pgtable_cpu[index] = paddr;58 59	return 0;60}61 62static size_t etnaviv_iommuv1_unmap(struct etnaviv_iommu_context *context,63	unsigned long iova, size_t size)64{65	struct etnaviv_iommuv1_context *v1_context = to_v1_context(context);66	unsigned int index = (iova - GPU_MEM_START) / SZ_4K;67 68	if (size != SZ_4K)69		return -EINVAL;70 71	v1_context->pgtable_cpu[index] = context->global->bad_page_dma;72 73	return SZ_4K;74}75 76static size_t etnaviv_iommuv1_dump_size(struct etnaviv_iommu_context *context)77{78	return PT_SIZE;79}80 81static void etnaviv_iommuv1_dump(struct etnaviv_iommu_context *context,82				 void *buf)83{84	struct etnaviv_iommuv1_context *v1_context = to_v1_context(context);85 86	memcpy(buf, v1_context->pgtable_cpu, PT_SIZE);87}88 89static void etnaviv_iommuv1_restore(struct etnaviv_gpu *gpu,90			     struct etnaviv_iommu_context *context)91{92	struct etnaviv_iommuv1_context *v1_context = to_v1_context(context);93	u32 pgtable;94 95	if (gpu->mmu_context)96		etnaviv_iommu_context_put(gpu->mmu_context);97	gpu->mmu_context = etnaviv_iommu_context_get(context);98 99	/* set base addresses */100	gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_RA, context->global->memory_base);101	gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_FE, context->global->memory_base);102	gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_TX, context->global->memory_base);103	gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_PEZ, context->global->memory_base);104	gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_PE, context->global->memory_base);105 106	/* set page table address in MC */107	pgtable = (u32)v1_context->pgtable_dma;108 109	gpu_write(gpu, VIVS_MC_MMU_FE_PAGE_TABLE, pgtable);110	gpu_write(gpu, VIVS_MC_MMU_TX_PAGE_TABLE, pgtable);111	gpu_write(gpu, VIVS_MC_MMU_PE_PAGE_TABLE, pgtable);112	gpu_write(gpu, VIVS_MC_MMU_PEZ_PAGE_TABLE, pgtable);113	gpu_write(gpu, VIVS_MC_MMU_RA_PAGE_TABLE, pgtable);114}115 116 117const struct etnaviv_iommu_ops etnaviv_iommuv1_ops = {118	.free = etnaviv_iommuv1_free,119	.map = etnaviv_iommuv1_map,120	.unmap = etnaviv_iommuv1_unmap,121	.dump_size = etnaviv_iommuv1_dump_size,122	.dump = etnaviv_iommuv1_dump,123	.restore = etnaviv_iommuv1_restore,124};125 126struct etnaviv_iommu_context *127etnaviv_iommuv1_context_alloc(struct etnaviv_iommu_global *global)128{129	struct etnaviv_iommuv1_context *v1_context;130	struct etnaviv_iommu_context *context;131 132	mutex_lock(&global->lock);133 134	/*135	 * MMUv1 does not support switching between different contexts without136	 * a stop the world operation, so we only support a single shared137	 * context with this version.138	 */139	if (global->v1.shared_context) {140		context = global->v1.shared_context;141		etnaviv_iommu_context_get(context);142		mutex_unlock(&global->lock);143		return context;144	}145 146	v1_context = kzalloc(sizeof(*v1_context), GFP_KERNEL);147	if (!v1_context) {148		mutex_unlock(&global->lock);149		return NULL;150	}151 152	v1_context->pgtable_cpu = dma_alloc_wc(global->dev, PT_SIZE,153					       &v1_context->pgtable_dma,154					       GFP_KERNEL);155	if (!v1_context->pgtable_cpu)156		goto out_free;157 158	memset32(v1_context->pgtable_cpu, global->bad_page_dma, PT_ENTRIES);159 160	context = &v1_context->base;161	context->global = global;162	kref_init(&context->refcount);163	mutex_init(&context->lock);164	INIT_LIST_HEAD(&context->mappings);165	drm_mm_init(&context->mm, GPU_MEM_START, PT_ENTRIES * SZ_4K);166	context->global->v1.shared_context = context;167 168	mutex_unlock(&global->lock);169 170	return context;171 172out_free:173	mutex_unlock(&global->lock);174	kfree(v1_context);175	return NULL;176}177