diff options
Diffstat (limited to 'src/gallium/drivers/vc4/kernel')
-rw-r--r-- | src/gallium/drivers/vc4/kernel/vc4_drv.h | 28 | ||||
-rw-r--r-- | src/gallium/drivers/vc4/kernel/vc4_gem.c | 70 | ||||
-rw-r--r-- | src/gallium/drivers/vc4/kernel/vc4_render_cl.c | 446 | ||||
-rw-r--r-- | src/gallium/drivers/vc4/kernel/vc4_validate.c | 306 |
4 files changed, 544 insertions, 306 deletions
diff --git a/src/gallium/drivers/vc4/kernel/vc4_drv.h b/src/gallium/drivers/vc4/kernel/vc4_drv.h index 8e9230b8949..83802dd774a 100644 --- a/src/gallium/drivers/vc4/kernel/vc4_drv.h +++ b/src/gallium/drivers/vc4/kernel/vc4_drv.h @@ -88,14 +88,9 @@ struct vc4_exec_info { uint32_t shader_state_count; bool found_tile_binning_mode_config_packet; - bool found_tile_rendering_mode_config_packet; bool found_start_tile_binning_packet; bool found_increment_semaphore_packet; - bool found_wait_on_semaphore_packet; uint8_t bin_tiles_x, bin_tiles_y; - uint32_t fb_width, fb_height; - uint32_t tile_alloc_init_block_mask; - uint32_t tile_alloc_init_block_last; struct drm_gem_cma_object *tile_alloc_bo; /** @@ -163,13 +158,10 @@ struct vc4_validated_shader_info /* vc4_validate.c */ int -vc4_validate_cl(struct drm_device *dev, - void *validated, - void *unvalidated, - uint32_t len, - bool is_bin, - bool has_bin, - struct vc4_exec_info *exec); +vc4_validate_bin_cl(struct drm_device *dev, + void *validated, + void *unvalidated, + struct vc4_exec_info *exec); int vc4_validate_shader_recs(struct drm_device *dev, struct vc4_exec_info *exec); @@ -177,4 +169,16 @@ vc4_validate_shader_recs(struct drm_device *dev, struct vc4_exec_info *exec); struct vc4_validated_shader_info * vc4_validate_shader(struct drm_gem_cma_object *shader_obj); +bool vc4_use_bo(struct vc4_exec_info *exec, + uint32_t hindex, + enum vc4_bo_mode mode, + struct drm_gem_cma_object **obj); + +int vc4_get_rcl(struct drm_device *dev, struct vc4_exec_info *exec); + +bool vc4_check_tex_size(struct vc4_exec_info *exec, + struct drm_gem_cma_object *fbo, + uint32_t offset, uint8_t tiling_format, + uint32_t width, uint32_t height, uint8_t cpp); + #endif /* VC4_DRV_H */ diff --git a/src/gallium/drivers/vc4/kernel/vc4_gem.c b/src/gallium/drivers/vc4/kernel/vc4_gem.c index e559ddd1d4e..e4b7fea5968 100644 --- a/src/gallium/drivers/vc4/kernel/vc4_gem.c +++ b/src/gallium/drivers/vc4/kernel/vc4_gem.c @@ -25,24 +25,26 @@ #include "vc4_drv.h" -int -vc4_cl_validate(struct drm_device *dev, struct vc4_exec_info *exec) +/* + * Copies in the user's binning command list and generates the validated bin + * CL, along with associated data (shader records, uniforms). + */ +static int +vc4_get_bcl(struct drm_device *dev, struct vc4_exec_info *exec) { struct drm_vc4_submit_cl *args = exec->args; void *temp = NULL; - void *bin, *render; + void *bin; int ret = 0; uint32_t bin_offset = 0; - uint32_t render_offset = bin_offset + args->bin_cl_size; - uint32_t shader_rec_offset = roundup(render_offset + - args->render_cl_size, 16); + uint32_t shader_rec_offset = roundup(bin_offset + args->bin_cl_size, + 16); uint32_t uniforms_offset = shader_rec_offset + args->shader_rec_size; uint32_t exec_size = uniforms_offset + args->uniforms_size; uint32_t temp_size = exec_size + (sizeof(struct vc4_shader_state) * args->shader_rec_count); - if (shader_rec_offset < render_offset || - uniforms_offset < shader_rec_offset || + if (uniforms_offset < shader_rec_offset || exec_size < uniforms_offset || args->shader_rec_count >= (UINT_MAX / sizeof(struct vc4_shader_state)) || @@ -66,7 +68,6 @@ vc4_cl_validate(struct drm_device *dev, struct vc4_exec_info *exec) goto fail; } bin = temp + bin_offset; - render = temp + render_offset; exec->shader_rec_u = temp + shader_rec_offset; exec->uniforms_u = temp + uniforms_offset; exec->shader_state = temp + exec_size; @@ -80,14 +81,6 @@ vc4_cl_validate(struct drm_device *dev, struct vc4_exec_info *exec) goto fail; } - ret = copy_from_user(render, - (void __user *)(uintptr_t)args->render_cl, - args->render_cl_size); - if (ret) { - DRM_ERROR("Failed to copy in render cl\n"); - goto fail; - } - ret = copy_from_user(exec->shader_rec_u, (void __user *)(uintptr_t)args->shader_rec, args->shader_rec_size); @@ -118,7 +111,6 @@ vc4_cl_validate(struct drm_device *dev, struct vc4_exec_info *exec) &exec->unref_list); exec->ct0ca = exec->exec_bo->paddr + bin_offset; - exec->ct1ca = exec->exec_bo->paddr + render_offset; exec->shader_rec_v = exec->exec_bo->vaddr + shader_rec_offset; exec->shader_rec_p = exec->exec_bo->paddr + shader_rec_offset; @@ -128,23 +120,10 @@ vc4_cl_validate(struct drm_device *dev, struct vc4_exec_info *exec) exec->uniforms_p = exec->exec_bo->paddr + uniforms_offset; exec->uniforms_size = args->uniforms_size; - ret = vc4_validate_cl(dev, - exec->exec_bo->vaddr + bin_offset, - bin, - args->bin_cl_size, - true, - args->bin_cl_size != 0, - exec); - if (ret) - goto fail; - - ret = vc4_validate_cl(dev, - exec->exec_bo->vaddr + render_offset, - render, - args->render_cl_size, - false, - args->bin_cl_size != 0, - exec); + ret = vc4_validate_bin_cl(dev, + exec->exec_bo->vaddr + bin_offset, + bin, + exec); if (ret) goto fail; @@ -155,4 +134,25 @@ fail: return ret; } +int +vc4_cl_validate(struct drm_device *dev, struct vc4_exec_info *exec) +{ + int ret = 0; + + if (exec->args->bin_cl_size != 0) { + ret = vc4_get_bcl(dev, exec); + if (ret) + goto fail; + } else { + exec->ct0ca = exec->ct0ea = 0; + } + + ret = vc4_get_rcl(dev, exec); + if (ret) + goto fail; + +fail: + return ret; +} + #endif /* USE_VC4_SIMULATOR */ diff --git a/src/gallium/drivers/vc4/kernel/vc4_render_cl.c b/src/gallium/drivers/vc4/kernel/vc4_render_cl.c new file mode 100644 index 00000000000..de6070fec72 --- /dev/null +++ b/src/gallium/drivers/vc4/kernel/vc4_render_cl.c @@ -0,0 +1,446 @@ +/* + * Copyright © 2014-2015 Broadcom + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/** + * DOC: Render command list generation + * + * In the VC4 driver, render command list generation is performed by the + * kernel instead of userspace. We do this because validating a + * user-submitted command list is hard to get right and has high CPU overhead, + * while the number of valid configurations for render command lists is + * actually fairly low. + */ + +#include "vc4_drv.h" +#include "vc4_packet.h" + +struct vc4_rcl_setup { + struct drm_gem_cma_object *color_read; + struct drm_gem_cma_object *color_ms_write; + struct drm_gem_cma_object *zs_read; + struct drm_gem_cma_object *zs_write; + + struct drm_gem_cma_object *rcl; + u32 next_offset; +}; + +static inline void rcl_u8(struct vc4_rcl_setup *setup, u8 val) +{ + *(u8 *)(setup->rcl->vaddr + setup->next_offset) = val; + setup->next_offset += 1; +} + +static inline void rcl_u16(struct vc4_rcl_setup *setup, u16 val) +{ + *(u16 *)(setup->rcl->vaddr + setup->next_offset) = val; + setup->next_offset += 2; +} + +static inline void rcl_u32(struct vc4_rcl_setup *setup, u32 val) +{ + *(u32 *)(setup->rcl->vaddr + setup->next_offset) = val; + setup->next_offset += 4; +} + + +/* + * Emits a no-op STORE_TILE_BUFFER_GENERAL. + * + * If we emit a PACKET_TILE_COORDINATES, it must be followed by a store of + * some sort before another load is triggered. + */ +static void vc4_store_before_load(struct vc4_rcl_setup *setup) +{ + rcl_u8(setup, VC4_PACKET_STORE_TILE_BUFFER_GENERAL); + rcl_u16(setup, + VC4_SET_FIELD(VC4_LOADSTORE_TILE_BUFFER_NONE, + VC4_LOADSTORE_TILE_BUFFER_BUFFER) | + VC4_STORE_TILE_BUFFER_DISABLE_COLOR_CLEAR | + VC4_STORE_TILE_BUFFER_DISABLE_ZS_CLEAR | + VC4_STORE_TILE_BUFFER_DISABLE_VG_MASK_CLEAR); + rcl_u32(setup, 0); /* no address, since we're in None mode */ +} + +/* + * Emits a PACKET_TILE_COORDINATES if one isn't already pending. + * + * The tile coordinates packet triggers a pending load if there is one, are + * used for clipping during rendering, and determine where loads/stores happen + * relative to their base address. + */ +static void vc4_tile_coordinates(struct vc4_rcl_setup *setup, + uint32_t x, uint32_t y) +{ + rcl_u8(setup, VC4_PACKET_TILE_COORDINATES); + rcl_u8(setup, x); + rcl_u8(setup, y); +} + +static void emit_tile(struct vc4_exec_info *exec, + struct vc4_rcl_setup *setup, + uint8_t x, uint8_t y, bool first, bool last) +{ + bool has_bin = exec->args->bin_cl_size != 0; + + /* Note that the load doesn't actually occur until the + * tile coords packet is processed, and only one load + * may be outstanding at a time. + */ + if (setup->color_read) { + rcl_u8(setup, VC4_PACKET_LOAD_TILE_BUFFER_GENERAL); + rcl_u16(setup, exec->args->color_read.bits); + rcl_u32(setup, + setup->color_read->paddr + + exec->args->color_read.offset); + } + + if (setup->zs_read) { + if (setup->color_read) { + /* Exec previous load. */ + vc4_tile_coordinates(setup, x, y); + vc4_store_before_load(setup); + } + + rcl_u8(setup, VC4_PACKET_LOAD_TILE_BUFFER_GENERAL); + rcl_u16(setup, exec->args->zs_read.bits); + rcl_u32(setup, + setup->zs_read->paddr + exec->args->zs_read.offset); + } + + /* Clipping depends on tile coordinates having been + * emitted, so we always need one here. + */ + vc4_tile_coordinates(setup, x, y); + + /* Wait for the binner before jumping to the first + * tile's lists. + */ + if (first && has_bin) + rcl_u8(setup, VC4_PACKET_WAIT_ON_SEMAPHORE); + + if (has_bin) { + rcl_u8(setup, VC4_PACKET_BRANCH_TO_SUB_LIST); + rcl_u32(setup, (exec->tile_alloc_bo->paddr + + (y * exec->bin_tiles_x + x) * 32)); + } + + if (setup->zs_write) { + rcl_u8(setup, VC4_PACKET_STORE_TILE_BUFFER_GENERAL); + rcl_u16(setup, exec->args->zs_write.bits | + (setup->color_ms_write ? + VC4_STORE_TILE_BUFFER_DISABLE_COLOR_CLEAR : 0)); + rcl_u32(setup, + (setup->zs_write->paddr + exec->args->zs_write.offset) | + ((last && !setup->color_ms_write) ? + VC4_LOADSTORE_TILE_BUFFER_EOF : 0)); + } + + if (setup->color_ms_write) { + if (setup->zs_write) { + /* Reset after previous store */ + vc4_tile_coordinates(setup, x, y); + } + + if (last) + rcl_u8(setup, VC4_PACKET_STORE_MS_TILE_BUFFER_AND_EOF); + else + rcl_u8(setup, VC4_PACKET_STORE_MS_TILE_BUFFER); + } +} + +static int vc4_create_rcl_bo(struct drm_device *dev, struct vc4_exec_info *exec, + struct vc4_rcl_setup *setup) +{ + bool has_bin = exec->args->bin_cl_size != 0; + uint8_t min_x_tile = exec->args->min_x_tile; + uint8_t min_y_tile = exec->args->min_y_tile; + uint8_t max_x_tile = exec->args->max_x_tile; + uint8_t max_y_tile = exec->args->max_y_tile; + uint8_t xtiles = max_x_tile - min_x_tile + 1; + uint8_t ytiles = max_y_tile - min_y_tile + 1; + uint8_t x, y; + uint32_t size, loop_body_size; + + size = VC4_PACKET_TILE_RENDERING_MODE_CONFIG_SIZE; + loop_body_size = VC4_PACKET_TILE_COORDINATES_SIZE; + + if (exec->args->flags & VC4_SUBMIT_CL_USE_CLEAR_COLOR) { + size += VC4_PACKET_CLEAR_COLORS_SIZE + + VC4_PACKET_TILE_COORDINATES_SIZE + + VC4_PACKET_STORE_TILE_BUFFER_GENERAL_SIZE; + } + + if (setup->color_read) { + loop_body_size += (VC4_PACKET_LOAD_TILE_BUFFER_GENERAL_SIZE); + } + if (setup->zs_read) { + if (setup->color_read) { + loop_body_size += VC4_PACKET_TILE_COORDINATES_SIZE; + loop_body_size += VC4_PACKET_STORE_TILE_BUFFER_GENERAL_SIZE; + } + loop_body_size += VC4_PACKET_LOAD_TILE_BUFFER_GENERAL_SIZE; + } + + if (has_bin) { + size += VC4_PACKET_WAIT_ON_SEMAPHORE_SIZE; + loop_body_size += VC4_PACKET_BRANCH_TO_SUB_LIST_SIZE; + } + + if (setup->zs_write) + loop_body_size += VC4_PACKET_LOAD_TILE_BUFFER_GENERAL_SIZE; + if (setup->color_ms_write) { + if (setup->zs_write) + loop_body_size += VC4_PACKET_TILE_COORDINATES_SIZE; + loop_body_size += VC4_PACKET_STORE_MS_TILE_BUFFER_SIZE; + } + size += xtiles * ytiles * loop_body_size; + + setup->rcl = drm_gem_cma_create(dev, size); + if (!setup->rcl) + return -ENOMEM; + list_addtail(&to_vc4_bo(&setup->rcl->base)->unref_head, + &exec->unref_list); + + rcl_u8(setup, VC4_PACKET_TILE_RENDERING_MODE_CONFIG); + rcl_u32(setup, + (setup->color_ms_write ? + (setup->color_ms_write->paddr + + exec->args->color_ms_write.offset) : + 0)); + rcl_u16(setup, exec->args->width); + rcl_u16(setup, exec->args->height); + rcl_u16(setup, exec->args->color_ms_write.bits); + + /* The tile buffer gets cleared when the previous tile is stored. If + * the clear values changed between frames, then the tile buffer has + * stale clear values in it, so we have to do a store in None mode (no + * writes) so that we trigger the tile buffer clear. + */ + if (exec->args->flags & VC4_SUBMIT_CL_USE_CLEAR_COLOR) { + rcl_u8(setup, VC4_PACKET_CLEAR_COLORS); + rcl_u32(setup, exec->args->clear_color[0]); + rcl_u32(setup, exec->args->clear_color[1]); + rcl_u32(setup, exec->args->clear_z); + rcl_u8(setup, exec->args->clear_s); + + vc4_tile_coordinates(setup, 0, 0); + + rcl_u8(setup, VC4_PACKET_STORE_TILE_BUFFER_GENERAL); + rcl_u16(setup, VC4_LOADSTORE_TILE_BUFFER_NONE); + rcl_u32(setup, 0); /* no address, since we're in None mode */ + } + + for (y = min_y_tile; y <= max_y_tile; y++) { + for (x = min_x_tile; x <= max_x_tile; x++) { + bool first = (x == min_x_tile && y == min_y_tile); + bool last = (x == max_x_tile && y == max_y_tile); + emit_tile(exec, setup, x, y, first, last); + } + } + + BUG_ON(setup->next_offset != size); + exec->ct1ca = setup->rcl->paddr; + exec->ct1ea = setup->rcl->paddr + setup->next_offset; + + return 0; +} + +static int vc4_rcl_surface_setup(struct vc4_exec_info *exec, + struct drm_gem_cma_object **obj, + struct drm_vc4_submit_rcl_surface *surf) +{ + uint8_t tiling = VC4_GET_FIELD(surf->bits, + VC4_LOADSTORE_TILE_BUFFER_TILING); + uint8_t buffer = VC4_GET_FIELD(surf->bits, + VC4_LOADSTORE_TILE_BUFFER_BUFFER); + uint8_t format = VC4_GET_FIELD(surf->bits, + VC4_LOADSTORE_TILE_BUFFER_FORMAT); + int cpp; + + if (surf->pad != 0) { + DRM_ERROR("Padding unset\n"); + return -EINVAL; + } + + if (surf->hindex == ~0) + return 0; + + if (!vc4_use_bo(exec, surf->hindex, VC4_MODE_RENDER, obj)) + return -EINVAL; + + if (surf->bits & ~(VC4_LOADSTORE_TILE_BUFFER_TILING_MASK | + VC4_LOADSTORE_TILE_BUFFER_BUFFER_MASK | + VC4_LOADSTORE_TILE_BUFFER_FORMAT_MASK)) { + DRM_ERROR("Unknown bits in load/store: 0x%04x\n", + surf->bits); + return -EINVAL; + } + + if (tiling > VC4_TILING_FORMAT_LT) { + DRM_ERROR("Bad tiling format\n"); + return -EINVAL; + } + + if (buffer == VC4_LOADSTORE_TILE_BUFFER_ZS) { + if (format != 0) { + DRM_ERROR("No color format should be set for ZS\n"); + return -EINVAL; + } + cpp = 4; + } else if (buffer == VC4_LOADSTORE_TILE_BUFFER_COLOR) { + switch (format) { + case VC4_LOADSTORE_TILE_BUFFER_BGR565: + case VC4_LOADSTORE_TILE_BUFFER_BGR565_DITHER: + cpp = 2; + break; + case VC4_LOADSTORE_TILE_BUFFER_RGBA8888: + cpp = 4; + break; + default: + DRM_ERROR("Bad tile buffer format\n"); + return -EINVAL; + } + } else { + DRM_ERROR("Bad load/store buffer %d.\n", buffer); + return -EINVAL; + } + + if (surf->offset & 0xf) { + DRM_ERROR("load/store buffer must be 16b aligned.\n"); + return -EINVAL; + } + + if (!vc4_check_tex_size(exec, *obj, surf->offset, tiling, + exec->args->width, exec->args->height, cpp)) { + return -EINVAL; + } + + return 0; +} + +static int +vc4_rcl_ms_surface_setup(struct vc4_exec_info *exec, + struct drm_gem_cma_object **obj, + struct drm_vc4_submit_rcl_surface *surf) +{ + uint8_t tiling = VC4_GET_FIELD(surf->bits, + VC4_RENDER_CONFIG_MEMORY_FORMAT); + uint8_t format = VC4_GET_FIELD(surf->bits, + VC4_RENDER_CONFIG_FORMAT); + int cpp; + + if (surf->pad != 0) { + DRM_ERROR("Padding unset\n"); + return -EINVAL; + } + + if (surf->bits & ~(VC4_RENDER_CONFIG_MEMORY_FORMAT_MASK | + VC4_RENDER_CONFIG_FORMAT_MASK)) { + DRM_ERROR("Unknown bits in render config: 0x%04x\n", + surf->bits); + return -EINVAL; + } + + if (surf->hindex == ~0) + return 0; + + if (!vc4_use_bo(exec, surf->hindex, VC4_MODE_RENDER, obj)) + return -EINVAL; + + if (tiling > VC4_TILING_FORMAT_LT) { + DRM_ERROR("Bad tiling format\n"); + return -EINVAL; + } + + switch (format) { + case VC4_RENDER_CONFIG_FORMAT_BGR565_DITHERED: + case VC4_RENDER_CONFIG_FORMAT_BGR565: + cpp = 2; + break; + case VC4_RENDER_CONFIG_FORMAT_RGBA8888: + cpp = 4; + break; + default: + DRM_ERROR("Bad tile buffer format\n"); + return -EINVAL; + } + + if (!vc4_check_tex_size(exec, *obj, surf->offset, tiling, + exec->args->width, exec->args->height, cpp)) { + return -EINVAL; + } + + return 0; +} + +int vc4_get_rcl(struct drm_device *dev, struct vc4_exec_info *exec) +{ + struct vc4_rcl_setup setup = {0}; + struct drm_vc4_submit_cl *args = exec->args; + bool has_bin = args->bin_cl_size != 0; + int ret; + + if (args->min_x_tile > args->max_x_tile || + args->min_y_tile > args->max_y_tile) { + DRM_ERROR("Bad render tile set (%d,%d)-(%d,%d)\n", + args->min_x_tile, args->min_y_tile, + args->max_x_tile, args->max_y_tile); + return -EINVAL; + } + + if (has_bin && + (args->max_x_tile > exec->bin_tiles_x || + args->max_y_tile > exec->bin_tiles_y)) { + DRM_ERROR("Render tiles (%d,%d) outside of bin config (%d,%d)\n", + args->max_x_tile, args->max_y_tile, + exec->bin_tiles_x, exec->bin_tiles_y); + return -EINVAL; + } + + ret = vc4_rcl_surface_setup(exec, &setup.color_read, &args->color_read); + if (ret) + return ret; + + ret = vc4_rcl_ms_surface_setup(exec, &setup.color_ms_write, + &args->color_ms_write); + if (ret) + return ret; + + ret = vc4_rcl_surface_setup(exec, &setup.zs_read, &args->zs_read); + if (ret) + return ret; + + ret = vc4_rcl_surface_setup(exec, &setup.zs_write, &args->zs_write); + if (ret) + return ret; + + /* We shouldn't even have the job submitted to us if there's no + * surface to write out. + */ + if (!setup.color_ms_write && !setup.zs_write) { + DRM_ERROR("RCL requires color or Z/S write\n"); + return -EINVAL; + } + + return vc4_create_rcl_bo(dev, exec, &setup); +} diff --git a/src/gallium/drivers/vc4/kernel/vc4_validate.c b/src/gallium/drivers/vc4/kernel/vc4_validate.c index 0a74a2c6db7..80b0e653d80 100644 --- a/src/gallium/drivers/vc4/kernel/vc4_validate.c +++ b/src/gallium/drivers/vc4/kernel/vc4_validate.c @@ -94,7 +94,7 @@ size_is_lt(uint32_t width, uint32_t height, int cpp) height <= 4 * utile_height(cpp)); } -static bool +bool vc4_use_bo(struct vc4_exec_info *exec, uint32_t hindex, enum vc4_bo_mode mode, @@ -147,10 +147,10 @@ gl_shader_rec_size(uint32_t pointer_bits) return 36 + attribute_count * 8; } -static bool -check_tex_size(struct vc4_exec_info *exec, struct drm_gem_cma_object *fbo, - uint32_t offset, uint8_t tiling_format, - uint32_t width, uint32_t height, uint8_t cpp) +bool +vc4_check_tex_size(struct vc4_exec_info *exec, struct drm_gem_cma_object *fbo, + uint32_t offset, uint8_t tiling_format, + uint32_t width, uint32_t height, uint8_t cpp) { uint32_t aligned_width, aligned_height, stride, size; uint32_t utile_w = utile_width(cpp); @@ -248,118 +248,6 @@ validate_increment_semaphore(VALIDATE_ARGS) } static int -validate_wait_on_semaphore(VALIDATE_ARGS) -{ - if (exec->found_wait_on_semaphore_packet) { - DRM_ERROR("Duplicate VC4_PACKET_WAIT_ON_SEMAPHORE\n"); - return -EINVAL; - } - exec->found_wait_on_semaphore_packet = true; - - if (!exec->found_increment_semaphore_packet) { - DRM_ERROR("VC4_PACKET_WAIT_ON_SEMAPHORE without " - "VC4_PACKET_INCREMENT_SEMAPHORE\n"); - return -EINVAL; - } - - return 0; -} - -static int -validate_branch_to_sublist(VALIDATE_ARGS) -{ - uint32_t offset; - - if (!exec->tile_alloc_bo) { - DRM_ERROR("VC4_PACKET_BRANCH_TO_SUB_LIST seen before " - "binner setup\n"); - return -EINVAL; - } - - if (!exec->found_wait_on_semaphore_packet) { - DRM_ERROR("Jumping to tile alloc before binning finished.\n"); - return -EINVAL; - } - - offset = *(uint32_t *)(untrusted + 0); - if (offset & exec->tile_alloc_init_block_mask || - offset > exec->tile_alloc_init_block_last) { - DRM_ERROR("VC4_PACKET_BRANCH_TO_SUB_LIST must jump to initial " - "tile allocation space.\n"); - return -EINVAL; - } - - *(uint32_t *)(validated + 0) = exec->tile_alloc_bo->paddr + offset; - - return 0; -} - -/** - * validate_loadstore_tile_buffer_general() - Validation for - * VC4_PACKET_LOAD_TILE_BUFFER_GENERAL and - * VC4_PACKET_STORE_TILE_BUFFER_GENERAL. - * - * The two packets are nearly the same, except for the TLB-clearing management - * bits not being present for loads. Additionally, while stores are executed - * immediately (using the current tile coordinates), loads are queued to be - * executed when the tile coordinates packet occurs. - * - * Note that coordinates packets are validated to be within the declared - * bin_x/y, which themselves are verified to match the rendering-configuration - * FB width and height (which the hardware uses to clip loads and stores). - */ -static int -validate_loadstore_tile_buffer_general(VALIDATE_ARGS) -{ - uint16_t packet_b01 = *(uint16_t *)(untrusted + 0); - struct drm_gem_cma_object *fbo; - uint32_t buffer_type = VC4_GET_FIELD(packet_b01, - VC4_LOADSTORE_TILE_BUFFER_BUFFER); - uint32_t untrusted_address, offset, cpp; - - switch (buffer_type) { - case VC4_LOADSTORE_TILE_BUFFER_NONE: - return 0; - case VC4_LOADSTORE_TILE_BUFFER_COLOR: - if (VC4_GET_FIELD(packet_b01, - VC4_LOADSTORE_TILE_BUFFER_FORMAT) == - VC4_LOADSTORE_TILE_BUFFER_RGBA8888) { - cpp = 4; - } else { - cpp = 2; - } - break; - - case VC4_LOADSTORE_TILE_BUFFER_Z: - case VC4_LOADSTORE_TILE_BUFFER_ZS: - cpp = 4; - break; - - default: - DRM_ERROR("Load/store type %d unsupported\n", buffer_type); - return -EINVAL; - } - - if (!vc4_use_handle(exec, 0, VC4_MODE_RENDER, &fbo)) - return -EINVAL; - - untrusted_address = *(uint32_t *)(untrusted + 2); - offset = untrusted_address & ~0xf; - - if (!check_tex_size(exec, fbo, offset, - VC4_GET_FIELD(packet_b01, - VC4_LOADSTORE_TILE_BUFFER_TILING), - exec->fb_width, exec->fb_height, cpp)) { - return -EINVAL; - } - - *(uint32_t *)(validated + 2) = (offset + fbo->paddr + - (untrusted_address & 0xf)); - - return 0; -} - -static int validate_indexed_prim_list(VALIDATE_ARGS) { struct drm_gem_cma_object *ib; @@ -552,9 +440,6 @@ validate_tile_binning_config(VALIDATE_ARGS) tile_allocation_size); return -EINVAL; } - exec->tile_alloc_init_block_mask = tile_alloc_init_block_size - 1; - exec->tile_alloc_init_block_last = tile_alloc_init_block_size * - (exec->bin_tiles_x * exec->bin_tiles_y - 1); if (*(uint32_t *)(untrusted + 8) != 0) { DRM_ERROR("TSDA offset != 0 unsupported\n"); @@ -572,141 +457,66 @@ validate_tile_binning_config(VALIDATE_ARGS) } static int -validate_tile_rendering_mode_config(VALIDATE_ARGS) -{ - struct drm_gem_cma_object *fbo; - uint32_t flags, offset, cpp; - - if (exec->found_tile_rendering_mode_config_packet) { - DRM_ERROR("Duplicate VC4_PACKET_TILE_RENDERING_MODE_CONFIG\n"); - return -EINVAL; - } - exec->found_tile_rendering_mode_config_packet = true; - - if (!vc4_use_handle(exec, 0, VC4_MODE_RENDER, &fbo)) - return -EINVAL; - - exec->fb_width = *(uint16_t *)(untrusted + 4); - exec->fb_height = *(uint16_t *)(untrusted + 6); - - flags = *(uint16_t *)(untrusted + 8); - if (VC4_GET_FIELD(flags, VC4_RENDER_CONFIG_FORMAT) == - VC4_RENDER_CONFIG_FORMAT_RGBA8888) { - cpp = 4; - } else { - cpp = 2; - } - - offset = *(uint32_t *)untrusted; - if (!check_tex_size(exec, fbo, offset, - VC4_GET_FIELD(flags, - VC4_RENDER_CONFIG_MEMORY_FORMAT), - exec->fb_width, exec->fb_height, cpp)) { - return -EINVAL; - } - - *(uint32_t *)validated = fbo->paddr + offset; - - return 0; -} - -static int -validate_tile_coordinates(VALIDATE_ARGS) -{ - uint8_t tile_x = *(uint8_t *)(untrusted + 0); - uint8_t tile_y = *(uint8_t *)(untrusted + 1); - - if (tile_x * 64 >= exec->fb_width || tile_y * 64 >= exec->fb_height) { - DRM_ERROR("Tile coordinates %d,%d > render config %dx%d\n", - tile_x, tile_y, exec->fb_width, exec->fb_height); - return -EINVAL; - } - - return 0; -} - -static int validate_gem_handles(VALIDATE_ARGS) { memcpy(exec->bo_index, untrusted, sizeof(exec->bo_index)); return 0; } -#define VC4_DEFINE_PACKET(packet, bin, render, name, func) \ - [packet] = { bin, render, packet ## _SIZE, name, func } +#define VC4_DEFINE_PACKET(packet, name, func) \ + [packet] = { packet ## _SIZE, name, func } static const struct cmd_info { - bool bin; - bool render; uint16_t len; const char *name; int (*func)(struct vc4_exec_info *exec, void *validated, void *untrusted); } cmd_info[] = { - VC4_DEFINE_PACKET(VC4_PACKET_HALT, 1, 1, "halt", NULL), - VC4_DEFINE_PACKET(VC4_PACKET_NOP, 1, 1, "nop", NULL), - VC4_DEFINE_PACKET(VC4_PACKET_FLUSH, 1, 1, "flush", NULL), - VC4_DEFINE_PACKET(VC4_PACKET_FLUSH_ALL, 1, 0, "flush all state", validate_flush_all), - VC4_DEFINE_PACKET(VC4_PACKET_START_TILE_BINNING, 1, 0, "start tile binning", validate_start_tile_binning), - VC4_DEFINE_PACKET(VC4_PACKET_INCREMENT_SEMAPHORE, 1, 0, "increment semaphore", validate_increment_semaphore), - VC4_DEFINE_PACKET(VC4_PACKET_WAIT_ON_SEMAPHORE, 0, 1, "wait on semaphore", validate_wait_on_semaphore), - /* BRANCH_TO_SUB_LIST is actually supported in the binner as well, but - * we only use it from the render CL in order to jump into the tile - * allocation BO. - */ - VC4_DEFINE_PACKET(VC4_PACKET_BRANCH_TO_SUB_LIST, 0, 1, "branch to sublist", validate_branch_to_sublist), - VC4_DEFINE_PACKET(VC4_PACKET_STORE_MS_TILE_BUFFER, 0, 1, "store MS resolved tile color buffer", NULL), - VC4_DEFINE_PACKET(VC4_PACKET_STORE_MS_TILE_BUFFER_AND_EOF, 0, 1, "store MS resolved tile color buffer and EOF", NULL), - - VC4_DEFINE_PACKET(VC4_PACKET_STORE_TILE_BUFFER_GENERAL, 0, 1, "Store Tile Buffer General", validate_loadstore_tile_buffer_general), - VC4_DEFINE_PACKET(VC4_PACKET_LOAD_TILE_BUFFER_GENERAL, 0, 1, "Load Tile Buffer General", validate_loadstore_tile_buffer_general), + VC4_DEFINE_PACKET(VC4_PACKET_HALT, "halt", NULL), + VC4_DEFINE_PACKET(VC4_PACKET_NOP, "nop", NULL), + VC4_DEFINE_PACKET(VC4_PACKET_FLUSH, "flush", NULL), + VC4_DEFINE_PACKET(VC4_PACKET_FLUSH_ALL, "flush all state", validate_flush_all), + VC4_DEFINE_PACKET(VC4_PACKET_START_TILE_BINNING, "start tile binning", validate_start_tile_binning), + VC4_DEFINE_PACKET(VC4_PACKET_INCREMENT_SEMAPHORE, "increment semaphore", validate_increment_semaphore), - VC4_DEFINE_PACKET(VC4_PACKET_GL_INDEXED_PRIMITIVE, 1, 1, "Indexed Primitive List", validate_indexed_prim_list), + VC4_DEFINE_PACKET(VC4_PACKET_GL_INDEXED_PRIMITIVE, "Indexed Primitive List", validate_indexed_prim_list), - VC4_DEFINE_PACKET(VC4_PACKET_GL_ARRAY_PRIMITIVE, 1, 1, "Vertex Array Primitives", validate_gl_array_primitive), + VC4_DEFINE_PACKET(VC4_PACKET_GL_ARRAY_PRIMITIVE, "Vertex Array Primitives", validate_gl_array_primitive), /* This is only used by clipped primitives (packets 48 and 49), which * we don't support parsing yet. */ - VC4_DEFINE_PACKET(VC4_PACKET_PRIMITIVE_LIST_FORMAT, 1, 1, "primitive list format", NULL), - - VC4_DEFINE_PACKET(VC4_PACKET_GL_SHADER_STATE, 1, 1, "GL Shader State", validate_gl_shader_state), - VC4_DEFINE_PACKET(VC4_PACKET_NV_SHADER_STATE, 1, 1, "NV Shader State", validate_nv_shader_state), - - VC4_DEFINE_PACKET(VC4_PACKET_CONFIGURATION_BITS, 1, 1, "configuration bits", NULL), - VC4_DEFINE_PACKET(VC4_PACKET_FLAT_SHADE_FLAGS, 1, 1, "flat shade flags", NULL), - VC4_DEFINE_PACKET(VC4_PACKET_POINT_SIZE, 1, 1, "point size", NULL), - VC4_DEFINE_PACKET(VC4_PACKET_LINE_WIDTH, 1, 1, "line width", NULL), - VC4_DEFINE_PACKET(VC4_PACKET_RHT_X_BOUNDARY, 1, 1, "RHT X boundary", NULL), - VC4_DEFINE_PACKET(VC4_PACKET_DEPTH_OFFSET, 1, 1, "Depth Offset", NULL), - VC4_DEFINE_PACKET(VC4_PACKET_CLIP_WINDOW, 1, 1, "Clip Window", NULL), - VC4_DEFINE_PACKET(VC4_PACKET_VIEWPORT_OFFSET, 1, 1, "Viewport Offset", NULL), - VC4_DEFINE_PACKET(VC4_PACKET_CLIPPER_XY_SCALING, 1, 1, "Clipper XY Scaling", NULL), + VC4_DEFINE_PACKET(VC4_PACKET_PRIMITIVE_LIST_FORMAT, "primitive list format", NULL), + + VC4_DEFINE_PACKET(VC4_PACKET_GL_SHADER_STATE, "GL Shader State", validate_gl_shader_state), + VC4_DEFINE_PACKET(VC4_PACKET_NV_SHADER_STATE, "NV Shader State", validate_nv_shader_state), + + VC4_DEFINE_PACKET(VC4_PACKET_CONFIGURATION_BITS, "configuration bits", NULL), + VC4_DEFINE_PACKET(VC4_PACKET_FLAT_SHADE_FLAGS, "flat shade flags", NULL), + VC4_DEFINE_PACKET(VC4_PACKET_POINT_SIZE, "point size", NULL), + VC4_DEFINE_PACKET(VC4_PACKET_LINE_WIDTH, "line width", NULL), + VC4_DEFINE_PACKET(VC4_PACKET_RHT_X_BOUNDARY, "RHT X boundary", NULL), + VC4_DEFINE_PACKET(VC4_PACKET_DEPTH_OFFSET, "Depth Offset", NULL), + VC4_DEFINE_PACKET(VC4_PACKET_CLIP_WINDOW, "Clip Window", NULL), + VC4_DEFINE_PACKET(VC4_PACKET_VIEWPORT_OFFSET, "Viewport Offset", NULL), + VC4_DEFINE_PACKET(VC4_PACKET_CLIPPER_XY_SCALING, "Clipper XY Scaling", NULL), /* Note: The docs say this was also 105, but it was 106 in the * initial userland code drop. */ - VC4_DEFINE_PACKET(VC4_PACKET_CLIPPER_Z_SCALING, 1, 1, "Clipper Z Scale and Offset", NULL), - - VC4_DEFINE_PACKET(VC4_PACKET_TILE_BINNING_MODE_CONFIG, 1, 0, "tile binning configuration", validate_tile_binning_config), + VC4_DEFINE_PACKET(VC4_PACKET_CLIPPER_Z_SCALING, "Clipper Z Scale and Offset", NULL), - VC4_DEFINE_PACKET(VC4_PACKET_TILE_RENDERING_MODE_CONFIG, 0, 1, "tile rendering mode configuration", validate_tile_rendering_mode_config), + VC4_DEFINE_PACKET(VC4_PACKET_TILE_BINNING_MODE_CONFIG, "tile binning configuration", validate_tile_binning_config), - VC4_DEFINE_PACKET(VC4_PACKET_CLEAR_COLORS, 0, 1, "Clear Colors", NULL), - - VC4_DEFINE_PACKET(VC4_PACKET_TILE_COORDINATES, 0, 1, "Tile Coordinates", validate_tile_coordinates), - - VC4_DEFINE_PACKET(VC4_PACKET_GEM_HANDLES, 1, 1, "GEM handles", validate_gem_handles), + VC4_DEFINE_PACKET(VC4_PACKET_GEM_HANDLES, "GEM handles", validate_gem_handles), }; int -vc4_validate_cl(struct drm_device *dev, - void *validated, - void *unvalidated, - uint32_t len, - bool is_bin, - bool has_bin, - struct vc4_exec_info *exec) +vc4_validate_bin_cl(struct drm_device *dev, + void *validated, + void *unvalidated, + struct vc4_exec_info *exec) { + uint32_t len = exec->args->bin_cl_size; uint32_t dst_offset = 0; uint32_t src_offset = 0; @@ -734,14 +544,6 @@ vc4_validate_cl(struct drm_device *dev, src_offset, cmd, info->name, info->len); #endif - if ((is_bin && !info->bin) || - (!is_bin && !info->render)) { - DRM_ERROR("0x%08x: packet %d (%s) invalid for %s\n", - src_offset, cmd, info->name, - is_bin ? "binner" : "render"); - return -EINVAL; - } - if (src_offset + info->len > len) { DRM_ERROR("0x%08x: packet %d (%s) length 0x%08x " "exceeds bounds (0x%08x)\n", @@ -772,30 +574,16 @@ vc4_validate_cl(struct drm_device *dev, break; } - if (is_bin) { - exec->ct0ea = exec->ct0ca + dst_offset; + exec->ct0ea = exec->ct0ca + dst_offset; - if (has_bin && !exec->found_start_tile_binning_packet) { - DRM_ERROR("Bin CL missing VC4_PACKET_START_TILE_BINNING\n"); - return -EINVAL; - } - } else { - if (!exec->found_tile_rendering_mode_config_packet) { - DRM_ERROR("Render CL missing VC4_PACKET_TILE_RENDERING_MODE_CONFIG\n"); - return -EINVAL; - } + if (!exec->found_start_tile_binning_packet) { + DRM_ERROR("Bin CL missing VC4_PACKET_START_TILE_BINNING\n"); + return -EINVAL; + } - /* Make sure that they actually consumed the semaphore - * increment from the bin CL. Otherwise a later submit would - * have render execute immediately. - */ - if (exec->found_wait_on_semaphore_packet != has_bin) { - DRM_ERROR("Render CL %s VC4_PACKET_WAIT_ON_SEMAPHORE\n", - exec->found_wait_on_semaphore_packet ? - "has" : "missing"); - return -EINVAL; - } - exec->ct1ea = exec->ct1ca + dst_offset; + if (!exec->found_increment_semaphore_packet) { + DRM_ERROR("Bin CL missing VC4_PACKET_INCREMENT_SEMAPHORE\n"); + return -EINVAL; } return 0; @@ -910,8 +698,8 @@ reloc_tex(struct vc4_exec_info *exec, tiling_format = VC4_TILING_FORMAT_T; } - if (!check_tex_size(exec, tex, offset + cube_map_stride * 5, - tiling_format, width, height, cpp)) { + if (!vc4_check_tex_size(exec, tex, offset + cube_map_stride * 5, + tiling_format, width, height, cpp)) { return false; } |