embox

Форк
0
/
etnaviv_iommu.c 
199 строк · 4.9 Кб
1
/**
2
 * @file etnaviv_iommu.c
3
 * @brief
4
 * @version
5
 * @date 25.03.2019
6
 */
7

8
#include <stdlib.h>
9

10
#include <asm-generic/dma-mapping.h>
11

12
#include "etnaviv_gpu.h"
13
#include "etnaviv_mmu.h"
14
#include "etnaviv_compat.h"
15

16
#include <etnaviv_xml/state_hi.xml.h>
17

18
#define PT_SIZE		SZ_2M
19
#define PT_ENTRIES	(PT_SIZE / sizeof(uint32_t))
20

21
#define GPU_MEM_START	0x80000000
22

23
struct etnaviv_iommu_domain_pgtable {
24
	uint32_t *pgtable;
25
	dma_addr_t paddr;
26
};
27

28
struct etnaviv_iommu_domain {
29
	struct device *dev;
30
	void *bad_page_cpu;
31
	dma_addr_t bad_page_dma;
32
	struct iommu_ops *ops;
33
	struct etnaviv_iommu_domain_pgtable pgtable;
34
};
35

36
static struct etnaviv_iommu_domain *to_etnaviv_domain(void *domain) {
37
	return domain;
38
}
39

40
static int pgtable_alloc(struct etnaviv_iommu_domain_pgtable *pgtable,
41
			 size_t size) {
42
	pgtable->pgtable = malloc(size);
43
	if (!pgtable->pgtable)
44
		return -ENOMEM;
45

46
	pgtable->paddr = (dma_addr_t) pgtable->pgtable;
47

48
	return 0;
49
}
50

51
static uint32_t pgtable_read(struct etnaviv_iommu_domain_pgtable *pgtable,
52
			   unsigned long iova) {
53
	/* calcuate index into page table */
54
	unsigned int index = (iova - GPU_MEM_START) / SZ_4K;
55
	phys_addr_t paddr;
56

57
	paddr = pgtable->pgtable[index];
58

59
	return paddr;
60
}
61

62
static void pgtable_write(struct etnaviv_iommu_domain_pgtable *pgtable,
63
			  unsigned long iova, phys_addr_t paddr) {
64
	/* calcuate index into page table */
65
	unsigned int index = (iova - GPU_MEM_START) / SZ_4K;
66

67
	pgtable->pgtable[index] = paddr;
68
}
69

70
static int __etnaviv_iommu_init(struct etnaviv_iommu_domain *etnaviv_domain) {
71
	uint32_t *p;
72
	int ret, i;
73

74
	etnaviv_domain->bad_page_cpu = malloc(SZ_4K);
75

76
	if (!etnaviv_domain->bad_page_cpu)
77
		return -ENOMEM;
78

79
	p = etnaviv_domain->bad_page_cpu;
80
	for (i = 0; i < SZ_4K / 4; i++)
81
		*p++ = 0xdead55aa;
82

83
	ret = pgtable_alloc(&etnaviv_domain->pgtable, PT_SIZE);
84
	if (ret < 0) {
85
		free(etnaviv_domain->bad_page_cpu);
86
		return ret;
87
	}
88

89
	for (i = 0; i < PT_ENTRIES; i++)
90
		etnaviv_domain->pgtable.pgtable[i] =
91
			etnaviv_domain->bad_page_dma;
92

93
	return 0;
94
}
95

96
static void etnaviv_domain_free(struct iommu_domain *domain) {
97
	struct etnaviv_iommu_domain *etnaviv_domain = to_etnaviv_domain(domain);
98

99
	free(etnaviv_domain->pgtable.pgtable);
100

101
	free(etnaviv_domain->bad_page_cpu);
102

103
	kfree(etnaviv_domain);
104
}
105

106
static int etnaviv_iommuv1_map(struct iommu_domain *domain, unsigned long iova,
107
	   phys_addr_t paddr, size_t size, int prot) {
108
	struct etnaviv_iommu_domain *etnaviv_domain = to_etnaviv_domain(domain);
109

110
	if (size != SZ_4K)
111
		return -EINVAL;
112

113
	pgtable_write(&etnaviv_domain->pgtable, iova, paddr);
114

115
	return 0;
116
}
117

118
static size_t etnaviv_iommuv1_unmap(struct iommu_domain *domain,
119
	unsigned long iova, size_t size) {
120
	struct etnaviv_iommu_domain *etnaviv_domain = to_etnaviv_domain(domain);
121

122
	if (size != SZ_4K)
123
		return -EINVAL;
124

125
	pgtable_write(&etnaviv_domain->pgtable, iova,
126
		      etnaviv_domain->bad_page_dma);
127

128
	return SZ_4K;
129
}
130

131
static phys_addr_t etnaviv_iommu_iova_to_phys(struct iommu_domain *domain,
132
	dma_addr_t iova) {
133
	struct etnaviv_iommu_domain *etnaviv_domain = to_etnaviv_domain(domain);
134

135
	return pgtable_read(&etnaviv_domain->pgtable, iova);
136
}
137

138
static size_t etnaviv_iommuv1_dump_size(struct iommu_domain *domain) {
139
	return PT_SIZE;
140
}
141

142
static void etnaviv_iommuv1_dump(struct iommu_domain *domain, void *buf) {
143
	struct etnaviv_iommu_domain *etnaviv_domain = to_etnaviv_domain(domain);
144

145
	memcpy(buf, etnaviv_domain->pgtable.pgtable, PT_SIZE);
146
}
147

148
struct etnaviv_iommu_ops etnaviv_iommu_ops = {
149
	.ops = {
150
		.domain_free = etnaviv_domain_free,
151
		.map = etnaviv_iommuv1_map,
152
		.unmap = etnaviv_iommuv1_unmap,
153
		.iova_to_phys = etnaviv_iommu_iova_to_phys,
154
		.pgsize_bitmap = SZ_4K,
155
	},
156
	.dump_size = etnaviv_iommuv1_dump_size,
157
	.dump = etnaviv_iommuv1_dump,
158
};
159

160
void etnaviv_iommuv1_restore(struct etnaviv_gpu *gpu) {
161
	struct etnaviv_iommu_domain *etnaviv_domain =
162
			to_etnaviv_domain(gpu->mmu.domain);
163
	uint32_t pgtable;
164

165
	/* set base addresses */
166
	gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_RA, gpu->memory_base);
167
	gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_FE, gpu->memory_base);
168
	gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_TX, gpu->memory_base);
169
	gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_PEZ, gpu->memory_base);
170
	gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_PE, gpu->memory_base);
171

172
	/* set page table address in MC */
173
	pgtable = (uint32_t) etnaviv_domain->pgtable.paddr;
174

175
	gpu_write(gpu, VIVS_MC_MMU_FE_PAGE_TABLE, pgtable);
176
	gpu_write(gpu, VIVS_MC_MMU_TX_PAGE_TABLE, pgtable);
177
	gpu_write(gpu, VIVS_MC_MMU_PE_PAGE_TABLE, pgtable);
178
	gpu_write(gpu, VIVS_MC_MMU_PEZ_PAGE_TABLE, pgtable);
179
	gpu_write(gpu, VIVS_MC_MMU_RA_PAGE_TABLE, pgtable);
180
}
181

182
int etnaviv_iommuv1_domain_init(struct etnaviv_gpu *gpu) {
183
	struct etnaviv_iommu_domain *etnaviv_domain;
184
	int ret;
185

186
	etnaviv_domain = (void *) &gpu->mmu.domain;
187

188
	memset(etnaviv_domain, 0, sizeof(*etnaviv_domain));
189

190
	etnaviv_domain->ops = &etnaviv_iommu_ops.ops;
191
	gpu->mmu.start_addr = GPU_MEM_START;
192
	gpu->mmu.end_addr = GPU_MEM_START + PT_ENTRIES * SZ_4K - 1;
193

194
	if ((ret = __etnaviv_iommu_init(etnaviv_domain))) {
195
		return ret;
196
	}
197

198
	return 0;
199
}
200

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.