embox

Форк
0
/
etnaviv_cmdbuf.c 
186 строк · 4.5 Кб
1
/*
2
 * Copyright (C) 2017 Etnaviv Project
3
 *
4
 * This program is free software; you can redistribute it and/or modify it
5
 * under the terms of the GNU General Public License version 2 as published by
6
 * the Free Software Foundation.
7
 *
8
 * This program is distributed in the hope that it will be useful, but WITHOUT
9
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
11
 * more details.
12
 *
13
 * You should have received a copy of the GNU General Public License along with
14
 * this program.  If not, see <http://www.gnu.org/licenses/>.
15
 */
16

17
#include <stdio.h>
18
#include <sys/mman.h>
19

20
#include <hal/cache.h>
21
#include <kernel/thread/sync/mutex.h>
22
#include <util/binalign.h>
23
#include <lib/libds/bitmap.h>
24
#include <mem/vmem.h>
25

26
#include "etnaviv_compat.h"
27
#include "etnaviv_cmdbuf.h"
28
#include "etnaviv_gpu.h"
29
#include "etnaviv_gem.h"
30
#include "etnaviv_drv.h"
31

32
#define SUBALLOC_SIZE		(256 * 1024)
33
#define SUBALLOC_GRANULE	(4096)
34
#define SUBALLOC_GRANULES	(SUBALLOC_SIZE / SUBALLOC_GRANULE)
35

36
struct etnaviv_cmdbuf_suballoc {
37
	struct etnaviv_gpu *gpu;
38
	void *addr;
39

40
	/* GPU mapping */
41
	uint32_t iova;
42

43
	/* allocation management */
44
	struct mutex lock;
45
	BITMAP_DECL(bitmap, SUBALLOC_GRANULES);
46
};
47

48
struct etnaviv_cmdbuf_suballoc *
49
etnaviv_cmdbuf_suballoc_new(struct etnaviv_gpu * gpu) {
50
	struct etnaviv_cmdbuf_suballoc *suballoc;
51
	int ret;
52

53
	assert(gpu);
54

55
	suballoc = sysmalloc(sizeof(struct etnaviv_cmdbuf_suballoc));
56
	if (!suballoc) {
57
		log_error("Failed to alloc suballoc structure");
58
		return ERR_PTR(-ENOMEM);
59
	}
60

61
	memset(suballoc, 0, sizeof(*suballoc));
62

63
	suballoc->gpu = gpu;
64
	suballoc->addr = sysmemalign(0x10000, SUBALLOC_SIZE);
65

66
	if (!suballoc->addr) {
67
		log_error("Failed to allocate suballoc buffer");
68
		goto free_suballoc;
69
	}
70

71
	if (vmem_set_flags(vmem_current_context(),
72
					(mmu_vaddr_t) suballoc->addr,
73
					SUBALLOC_SIZE,
74
					PROT_WRITE | PROT_READ | PROT_NOCACHE)) {
75
		log_error("Failed to set vmem flags");
76
		goto free_dma;
77
	}
78
	mmu_flush_tlb();
79
	dcache_flush(suballoc->addr, SUBALLOC_SIZE);
80

81
	memset(suballoc->addr, 0, SUBALLOC_SIZE);
82

83
	mutex_init(&suballoc->lock);
84

85
	ret = etnaviv_iommu_get_suballoc_va(gpu, (dma_addr_t) suballoc->addr,
86
					     SUBALLOC_SIZE,
87
					    &suballoc->iova);
88
	if (ret) {
89
		log_error("Failed to get suballoc VA");
90
		goto free_dma;
91
	}
92

93
	return suballoc;
94

95
free_dma:
96
	sysfree(suballoc->addr);
97
free_suballoc:
98
	sysfree(suballoc);
99

100
	return NULL;
101
}
102

103
void etnaviv_cmdbuf_suballoc_destroy(struct etnaviv_cmdbuf_suballoc *suballoc) {
104
	kfree(suballoc->addr);
105
	kfree(suballoc);
106
}
107

108
struct etnaviv_cmdbuf *etnaviv_cmdbuf_new(
109
		struct etnaviv_cmdbuf_suballoc *suballoc, uint32_t size,
110
		size_t nr_bos) {
111
	struct etnaviv_cmdbuf *cmdbuf;
112
	int cmdbuf_size = (sizeof(struct etnaviv_cmdbuf)) +
113
		(sizeof(struct etnaviv_vram_mapping)) * nr_bos;
114
	int off, granules;
115

116
	assert(suballoc);
117

118
	mutex_lock(&suballoc->lock);
119

120
	granules = binalign_bound(size, SUBALLOC_GRANULE) / SUBALLOC_GRANULE;
121
	off = bitmap_find_zero_bit(suballoc->bitmap, granules, 0);
122

123
	if (off == SUBALLOC_GRANULES) {
124
		log_error("Suballoc bitmap is full");
125
		return NULL;
126
	}
127

128
	if (!(cmdbuf = sysmalloc(cmdbuf_size))) {
129
		log_error("Failed to allocate cmdbuf");
130
		return NULL;
131
	}
132

133
	*cmdbuf = (struct etnaviv_cmdbuf) {
134
		.suballoc = suballoc,
135
		.size = size,
136
		.suballoc_offset = off * SUBALLOC_GRANULE,
137
		.vaddr = suballoc->addr + off * SUBALLOC_GRANULE,
138
	};
139

140
	log_debug("Cmdbuf info: addr %p suballoc offt 0x%x size 0x%x",
141
			cmdbuf, cmdbuf->suballoc_offset, size);
142

143
	for (int i = 0; i < granules; i++) {
144
		bitmap_set_bit(suballoc->bitmap, off + i);
145
	}
146

147
	mutex_unlock(&suballoc->lock);
148

149
	return cmdbuf;
150
}
151

152
void etnaviv_cmdbuf_free(struct etnaviv_cmdbuf *cmdbuf) {
153
	struct etnaviv_cmdbuf_suballoc *suballoc;
154
	int off, granules;
155

156
	assert(cmdbuf);
157
	assert(cmdbuf->suballoc);
158

159
	suballoc = cmdbuf->suballoc;
160

161
	mutex_lock(&suballoc->lock);
162
	off = cmdbuf->suballoc_offset / SUBALLOC_GRANULE;
163
	granules = cmdbuf->size / SUBALLOC_GRANULE;
164
	for (int i = 0; i < granules; i++) {
165
		bitmap_clear_bit(suballoc->bitmap, off + i);
166
	}
167
	mutex_unlock(&suballoc->lock);
168

169
	sysfree(cmdbuf);
170
}
171

172
uint32_t etnaviv_cmdbuf_get_va(struct etnaviv_cmdbuf *buf) {
173
	assert(buf);
174

175
	log_debug("suballoc %p iova %p offset %p",
176
			buf->suballoc,
177
			(void*) buf->suballoc->iova,
178
			(void*) buf->suballoc_offset);
179
	return ((uint32_t) buf->vaddr) - 0x10000000;
180
}
181

182
dma_addr_t etnaviv_cmdbuf_get_pa(struct etnaviv_cmdbuf *buf) {
183
	assert(buf);
184
	assert(buf->suballoc);
185
	return (dma_addr_t) (buf->suballoc->addr + buf->suballoc_offset);
186
}
187

188

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

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

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

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