int etna_free(struct etna_ctx *ctx) { if(ctx == NULL) return ETNA_INVALID_ADDR; /* Free kernel command queue */ etna_queue_free(ctx->queue); #ifdef GCABI_HAS_CONTEXT /* Free context buffer */ etna_bo_del(ctx->conn, ctx->ctx_bo, NULL); #endif /* Free command buffers */ for(int x=0; x<NUM_COMMAND_BUFFERS; ++x) { viv_user_signal_destroy(ctx->conn, ctx->cmdbufi[x].sig_id); etna_bo_del(ctx->conn, ctx->cmdbufi[x].bo, NULL); ETNA_FREE(ctx->cmdbuf[x]); } viv_user_signal_destroy(ctx->conn, ctx->sig_id); #ifndef GCABI_HAS_CONTEXT gpu_context_free(ctx); #endif ETNA_FREE(ctx); return ETNA_OK; }
int etna_queue_free(struct etna_queue *queue) { if(queue == NULL) return ETNA_INVALID_ADDR; ETNA_FREE(queue->queue); ETNA_FREE(queue); return ETNA_OK; }
struct etna_bo* etna_bo_new(struct viv_conn *conn, size_t bytes, uint32_t flags) { struct etna_bo *mem = ETNA_CALLOC_STRUCT(etna_bo); if(mem == NULL) return NULL; if((flags & DRM_ETNA_GEM_TYPE_MASK) == DRM_ETNA_GEM_TYPE_CMD) { mem->bo_type = ETNA_BO_TYPE_CONTIGUOUS; /* Command buffers must be allocated with viv_alloc_contiguous */ if(viv_alloc_contiguous(conn, bytes, &mem->address, &mem->logical, &mem->size)!=0) { ETNA_FREE(mem); return NULL; } } else { enum viv_surf_type type = VIV_SURF_UNKNOWN; enum viv_pool pool = VIV_POOL_DEFAULT; /* Convert GEM bits to surface type */ switch(flags & DRM_ETNA_GEM_TYPE_MASK) { case DRM_ETNA_GEM_TYPE_IDX: type = VIV_SURF_INDEX; break; case DRM_ETNA_GEM_TYPE_VTX: type = VIV_SURF_VERTEX; break; case DRM_ETNA_GEM_TYPE_TEX: type = VIV_SURF_TEXTURE; break; case DRM_ETNA_GEM_TYPE_RT: type = VIV_SURF_RENDER_TARGET; break; case DRM_ETNA_GEM_TYPE_ZS: type = VIV_SURF_DEPTH; break; case DRM_ETNA_GEM_TYPE_HZ: type = VIV_SURF_HIERARCHICAL_DEPTH; break; case DRM_ETNA_GEM_TYPE_BMP: type = VIV_SURF_BITMAP; break; case DRM_ETNA_GEM_TYPE_TS: type = VIV_SURF_TILE_STATUS; break; default: /* Invalid type */ ETNA_FREE(mem); return NULL; break; } mem->bo_type = ETNA_BO_TYPE_VIDMEM; mem->type = type; if(viv_alloc_linear_vidmem(conn, bytes, ETNA_VIDMEM_ALIGNMENT, type, pool, &mem->node, &mem->size)!=0) { #ifdef DEBUG fprintf(stderr, "Error allocating memory\n"); #endif return NULL; } #ifdef DEBUG printf("Allocated: mem=%p node=%08x size=%08x\n", mem, (uint32_t)mem->node, mem->size); #endif int status = etna_bo_lock(conn, mem); if(status != ETNA_OK) { etna_bo_del(conn, mem, NULL); return NULL; } } return mem; }
int etna_bo_del(struct viv_conn *conn, struct etna_bo *mem, struct etna_queue *queue) { int rv = ETNA_OK; if(mem == NULL) return ETNA_OK; switch(mem->bo_type) { case ETNA_BO_TYPE_VIDMEM: if(mem->logical != NULL) { if((rv = etna_bo_unlock(conn, mem, queue)) != ETNA_OK) { printf("etna: Warning: could not unlock memory\n"); } } if(queue) { if((rv = etna_queue_free_vidmem(queue, mem->node)) != ETNA_OK) { printf("etna: Warning: could not queue free video memory\n"); } } else { if((rv = viv_free_vidmem(conn, mem->node)) != ETNA_OK) { printf("etna: Warning: could not free video memory\n"); } } break; case ETNA_BO_TYPE_VIDMEM_EXTERNAL: if((rv = etna_bo_unlock(conn, mem, queue)) != ETNA_OK) { printf("etna: Warning: could not unlock memory\n"); } break; case ETNA_BO_TYPE_USERMEM: if(queue) { rv = etna_queue_unmap_user_memory(queue, mem->logical, mem->size, mem->usermem_info, mem->address); } else { rv = viv_unmap_user_memory(conn, mem->logical, mem->size, mem->usermem_info, mem->address); } break; case ETNA_BO_TYPE_CONTIGUOUS: if(queue) { rv = etna_queue_free_contiguous(queue, mem->size, mem->address, mem->logical); } else { rv = viv_free_contiguous(conn, mem->size, mem->address, mem->logical); } break; case ETNA_BO_TYPE_PHYSICAL: if(munmap(mem->logical, mem->size) < 0) { rv = ETNA_OUT_OF_MEMORY; } break; } ETNA_FREE(mem); return rv; }
int etna_free(struct etna_ctx *ctx) { if(ctx == NULL) return ETNA_INVALID_ADDR; /* Free kernel command queue */ etna_queue_free(ctx->queue); #ifdef GCABI_HAVE_CONTEXT /* Free context buffer */ gpu_context_free_buffer(ctx, &ctx->ctx_info, false); #endif /* Free command buffers */ for(int x=0; x<NUM_COMMAND_BUFFERS; ++x) { viv_free_contiguous(ctx->conn, ctx->cmdbufi[x].bytes, (viv_addr_t)ctx->cmdbufi[x].physical, VIV_TO_PTR(ctx->cmdbufi[x].logical)); ETNA_FREE(ctx->cmdbuf[x]); } ETNA_FREE(ctx); return ETNA_OK; }
int etna_bswap_free(etna_bswap_buffers *bufs) { bufs->terminate = true; /* signal ready signals, to prevent thread from waiting forever for buffer to become ready */ for(int idx=0; idx<ETNA_BSWAP_NUM_BUFFERS; ++idx) (void)viv_user_signal_signal(bufs->buf[idx].sig_id_ready, 1); (void)pthread_join(bufs->thread, NULL); for(int idx=0; idx<ETNA_BSWAP_NUM_BUFFERS; ++idx) etna_bswap_destroy_buffer(&bufs->buf[idx]); ETNA_FREE(bufs); return ETNA_OK; }
struct etna_bo *etna_bo_from_usermem(struct viv_conn *conn, void *memory, size_t size) { struct etna_bo *mem = ETNA_CALLOC_STRUCT(etna_bo); if(mem == NULL) return NULL; mem->bo_type = ETNA_BO_TYPE_USERMEM; mem->logical = memory; mem->size = size; if(viv_map_user_memory(conn, memory, size, &mem->usermem_info, &mem->address)!=0) { ETNA_FREE(mem); return NULL; } return mem; }
struct etna_bo *etna_bo_from_fbdev(struct viv_conn *conn, int fd, size_t offset, size_t size) { struct fb_fix_screeninfo finfo; struct etna_bo *mem = ETNA_CALLOC_STRUCT(etna_bo); if(mem == NULL) return NULL; if(ioctl(fd, FBIOGET_FSCREENINFO, &finfo)) goto error; mem->bo_type = ETNA_BO_TYPE_PHYSICAL; if((mem->logical = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == NULL) goto error; mem->address = finfo.smem_start + offset; mem->size = size; return mem; error: ETNA_FREE(mem); return NULL; }
static int gpu_context_initialize(struct etna_ctx *ctx) { gcoCONTEXT vctx = ETNA_CALLOC_STRUCT(_gcoCONTEXT); if(vctx == NULL) { return ETNA_OUT_OF_MEMORY; } vctx->object.type = gcvOBJ_CONTEXT; vctx->id = 0x0; /* Actual ID will be returned here by kernel */ vctx->pipe3DIndex = vctx->pipe2DIndex = /* Any non-zero value will do, as kernel does not use */ vctx->linkIndex = vctx->inUseIndex = 1; /* the actual values, just checks for zero */ vctx->initialPipe = ETNA_PIPE_3D; /* Pipe to be active at beginning of context buffer */ vctx->entryPipe = ETNA_PIPE_3D; /* Pipe at beginning of command buffer (needs to be added to context as well if */ /* pipe at end of context is different from entry pipe) */ vctx->currentPipe = ETNA_PIPE_3D; /* Pipe at end of command buffer */ /* CPU address of buffer */ vctx->logical = 0; /* Number of bytes to read from command buffer by GPU */ vctx->bufferSize = 0; /* Logical address of two NOP words at end of command buffer */ vctx->link = NULL; /* Logical address of inUse flag as returned from kernel (within * consecutive array), must have one word of NOP */ vctx->inUse = NULL; ctx->ctx = VIV_TO_HANDLE(vctx); /* Allocate initial context buffer */ /* XXX DRM_ETNA_GEM_CACHE_xxx */ if((ctx->ctx_bo = etna_bo_new(ctx->conn, COMMAND_BUFFER_SIZE, DRM_ETNA_GEM_TYPE_CMD)) == NULL) { ETNA_FREE(vctx); return ETNA_OUT_OF_MEMORY; } /* Set context to initial sane values */ gpu_context_clear(ctx); return ETNA_OK; }
int etna_create(struct viv_conn *conn, struct etna_ctx **ctx_out) { int rv; if(ctx_out == NULL) return ETNA_INVALID_ADDR; struct etna_ctx *ctx = ETNA_CALLOC_STRUCT(etna_ctx); if(ctx == NULL) return ETNA_OUT_OF_MEMORY; ctx->conn = conn; if(gpu_context_initialize(ctx) != ETNA_OK) { ETNA_FREE(ctx); return ETNA_INTERNAL_ERROR; } /* Create synchronization signal */ if(viv_user_signal_create(conn, 0, &ctx->sig_id) != 0) /* automatic resetting signal */ { #ifdef DEBUG fprintf(stderr, "Cannot create user signal\n"); #endif return ETNA_INTERNAL_ERROR; } #ifdef DEBUG fprintf(stderr, "Created user signal %i\n", ctx->sig_id); #endif /* Allocate command buffers, and create a synchronization signal for each. * Also signal the synchronization signal for the buffers to tell that the buffers are ready for use. */ for(int x=0; x<NUM_COMMAND_BUFFERS; ++x) { ctx->cmdbuf[x] = ETNA_CALLOC_STRUCT(_gcoCMDBUF); if((ctx->cmdbufi[x].bo = etna_bo_new(conn, COMMAND_BUFFER_SIZE, DRM_ETNA_GEM_TYPE_CMD))==NULL) { #ifdef DEBUG fprintf(stderr, "Error allocating host memory for command buffer\n"); #endif return ETNA_OUT_OF_MEMORY; } ctx->cmdbuf[x]->object.type = gcvOBJ_COMMANDBUFFER; #ifdef GCABI_CMDBUF_HAS_PHYSICAL ctx->cmdbuf[x]->physical = PTR_TO_VIV((void*)etna_bo_gpu_address(ctx->cmdbufi[x].bo)); ctx->cmdbuf[x]->bytes = ctx->cmdbufi[x].bytes; #endif ctx->cmdbuf[x]->logical = PTR_TO_VIV((void*)etna_bo_map(ctx->cmdbufi[x].bo)); if(viv_user_signal_create(conn, 0, &ctx->cmdbufi[x].sig_id) != 0 || viv_user_signal_signal(conn, ctx->cmdbufi[x].sig_id, 1) != 0) { #ifdef DEBUG fprintf(stderr, "Cannot create user signal\n"); #endif return ETNA_INTERNAL_ERROR; } #ifdef DEBUG fprintf(stderr, "Allocated buffer %i: phys=%08x log=%08x bytes=%08x [signal %i]\n", x, (uint32_t)buf0_physical, (uint32_t)buf0_logical, buf0_bytes, ctx->cmdbufi[x].sig); #endif } /* Allocate command queue */ if((rv = etna_queue_create(ctx, &ctx->queue)) != ETNA_OK) { #ifdef DEBUG fprintf(stderr, "Error allocating kernel command queue\n"); #endif return rv; } /* Set current buffer to ETNA_NO_BUFFER, to signify that we need to switch to buffer 0 before * queueing of commands can be started. */ ctx->cur_buf = ETNA_NO_BUFFER; *ctx_out = ctx; return ETNA_OK; }