21
#include <kernel/thread/sync/mutex.h>
22
#include <util/binalign.h>
23
#include <lib/libds/bitmap.h>
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"
32
#define SUBALLOC_SIZE (256 * 1024)
33
#define SUBALLOC_GRANULE (4096)
34
#define SUBALLOC_GRANULES (SUBALLOC_SIZE / SUBALLOC_GRANULE)
36
struct etnaviv_cmdbuf_suballoc {
37
struct etnaviv_gpu *gpu;
45
BITMAP_DECL(bitmap, SUBALLOC_GRANULES);
48
struct etnaviv_cmdbuf_suballoc *
49
etnaviv_cmdbuf_suballoc_new(struct etnaviv_gpu * gpu) {
50
struct etnaviv_cmdbuf_suballoc *suballoc;
55
suballoc = sysmalloc(sizeof(struct etnaviv_cmdbuf_suballoc));
57
log_error("Failed to alloc suballoc structure");
58
return ERR_PTR(-ENOMEM);
61
memset(suballoc, 0, sizeof(*suballoc));
64
suballoc->addr = sysmemalign(0x10000, SUBALLOC_SIZE);
66
if (!suballoc->addr) {
67
log_error("Failed to allocate suballoc buffer");
71
if (vmem_set_flags(vmem_current_context(),
72
(mmu_vaddr_t) suballoc->addr,
74
PROT_WRITE | PROT_READ | PROT_NOCACHE)) {
75
log_error("Failed to set vmem flags");
79
dcache_flush(suballoc->addr, SUBALLOC_SIZE);
81
memset(suballoc->addr, 0, SUBALLOC_SIZE);
83
mutex_init(&suballoc->lock);
85
ret = etnaviv_iommu_get_suballoc_va(gpu, (dma_addr_t) suballoc->addr,
89
log_error("Failed to get suballoc VA");
96
sysfree(suballoc->addr);
103
void etnaviv_cmdbuf_suballoc_destroy(struct etnaviv_cmdbuf_suballoc *suballoc) {
104
kfree(suballoc->addr);
108
struct etnaviv_cmdbuf *etnaviv_cmdbuf_new(
109
struct etnaviv_cmdbuf_suballoc *suballoc, uint32_t size,
111
struct etnaviv_cmdbuf *cmdbuf;
112
int cmdbuf_size = (sizeof(struct etnaviv_cmdbuf)) +
113
(sizeof(struct etnaviv_vram_mapping)) * nr_bos;
118
mutex_lock(&suballoc->lock);
120
granules = binalign_bound(size, SUBALLOC_GRANULE) / SUBALLOC_GRANULE;
121
off = bitmap_find_zero_bit(suballoc->bitmap, granules, 0);
123
if (off == SUBALLOC_GRANULES) {
124
log_error("Suballoc bitmap is full");
128
if (!(cmdbuf = sysmalloc(cmdbuf_size))) {
129
log_error("Failed to allocate cmdbuf");
133
*cmdbuf = (struct etnaviv_cmdbuf) {
134
.suballoc = suballoc,
136
.suballoc_offset = off * SUBALLOC_GRANULE,
137
.vaddr = suballoc->addr + off * SUBALLOC_GRANULE,
140
log_debug("Cmdbuf info: addr %p suballoc offt 0x%x size 0x%x",
141
cmdbuf, cmdbuf->suballoc_offset, size);
143
for (int i = 0; i < granules; i++) {
144
bitmap_set_bit(suballoc->bitmap, off + i);
147
mutex_unlock(&suballoc->lock);
152
void etnaviv_cmdbuf_free(struct etnaviv_cmdbuf *cmdbuf) {
153
struct etnaviv_cmdbuf_suballoc *suballoc;
157
assert(cmdbuf->suballoc);
159
suballoc = cmdbuf->suballoc;
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);
167
mutex_unlock(&suballoc->lock);
172
uint32_t etnaviv_cmdbuf_get_va(struct etnaviv_cmdbuf *buf) {
175
log_debug("suballoc %p iova %p offset %p",
177
(void*) buf->suballoc->iova,
178
(void*) buf->suballoc_offset);
179
return ((uint32_t) buf->vaddr) - 0x10000000;
182
dma_addr_t etnaviv_cmdbuf_get_pa(struct etnaviv_cmdbuf *buf) {
184
assert(buf->suballoc);
185
return (dma_addr_t) (buf->suballoc->addr + buf->suballoc_offset);