diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index 60fa75ff7d09e..541d9d5aa0f87 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -793,6 +793,11 @@ struct vc4_exec_info { * (where each tile's binned CL will start) */ uint32_t tile_alloc_offset; + /* Stride between adjacent tiles' initial alloc blocks. Equals the + * initial block size programmed in the binning config, and is used + * as the per-tile stride when emitting the RCL branches. + */ + u32 tile_alloc_stride; /* Bitmask of which binner slots are freed when this job completes. */ uint32_t bin_slots; diff --git a/drivers/gpu/drm/vc4/vc4_irq.c b/drivers/gpu/drm/vc4/vc4_irq.c index 69b399f3b8027..08340991e5a75 100644 --- a/drivers/gpu/drm/vc4/vc4_irq.c +++ b/drivers/gpu/drm/vc4/vc4_irq.c @@ -104,7 +104,7 @@ vc4_overflow_mem_work(struct work_struct *work) vc4->bin_alloc_overflow = BIT(bin_bo_slot); V3D_WRITE(V3D_BPOA, bo->base.dma_addr + bin_bo_slot * vc4->bin_alloc_size); - V3D_WRITE(V3D_BPOS, bo->base.base.size); + V3D_WRITE(V3D_BPOS, vc4->bin_alloc_size); V3D_WRITE(V3D_INTCTL, V3D_INT_OUTOMEM); V3D_WRITE(V3D_INTENA, V3D_INT_OUTOMEM); spin_unlock_irqrestore(&vc4->job_lock, irqflags); @@ -352,6 +352,18 @@ void vc4_irq_reset(struct drm_device *dev) V3D_WRITE(V3D_INTENA, V3D_DRIVER_IRQS); spin_lock_irqsave(&vc4->job_lock, irqflags); + + /* + * The reset wiped the binner's hardware state, and the job that may + * have been reading overflow memory is torn down just below. Free the + * current overflow slot and clear the overflow registers so the + * re-queued BIN job restarts from a clean OOM state. + */ + vc4->bin_alloc_used &= ~vc4->bin_alloc_overflow; + vc4->bin_alloc_overflow = 0; + V3D_WRITE(V3D_BPOA, 0); + V3D_WRITE(V3D_BPOS, 0); + vc4_cancel_bin_job(dev); vc4_irq_finish_render_job(dev); spin_unlock_irqrestore(&vc4->job_lock, irqflags); diff --git a/drivers/gpu/drm/vc4/vc4_render_cl.c b/drivers/gpu/drm/vc4/vc4_render_cl.c index 14079853338eb..a34cbbbc932c5 100644 --- a/drivers/gpu/drm/vc4/vc4_render_cl.c +++ b/drivers/gpu/drm/vc4/vc4_render_cl.c @@ -183,7 +183,8 @@ static void emit_tile(struct vc4_exec_info *exec, if (has_bin) { rcl_u8(setup, VC4_PACKET_BRANCH_TO_SUB_LIST); rcl_u32(setup, (exec->tile_alloc_offset + - (y * exec->bin_tiles_x + x) * 32)); + (y * exec->bin_tiles_x + x) * + exec->tile_alloc_stride)); } if (setup->msaa_color_write) { diff --git a/drivers/gpu/drm/vc4/vc4_validate.c b/drivers/gpu/drm/vc4/vc4_validate.c index 1e7bdda556984..e7f76b4b28b0a 100644 --- a/drivers/gpu/drm/vc4/vc4_validate.c +++ b/drivers/gpu/drm/vc4/vc4_validate.c @@ -356,8 +356,9 @@ validate_tile_binning_config(VALIDATE_ARGS) struct drm_device *dev = exec->exec_bo->base.dev; struct vc4_dev *vc4 = to_vc4_dev(dev); uint8_t flags; - uint32_t tile_state_size; + u32 tile_state_size, tile_state_aligned; uint32_t tile_count, bin_addr; + u8 init_block; int bin_slot; if (exec->found_tile_binning_mode_config_packet) { @@ -405,13 +406,35 @@ validate_tile_binning_config(VALIDATE_ARGS) tile_state_size = 48 * tile_count; /* Since the tile alloc array will follow us, align. */ - exec->tile_alloc_offset = bin_addr + roundup(tile_state_size, 4096); + tile_state_aligned = roundup(tile_state_size, 4096); + exec->tile_alloc_offset = bin_addr + tile_state_aligned; + + /* + * Pick the largest initial tile-alloc block that still fits the slot. + * Larger initial blocks keep more tiles' binned lists off the + * continuation-block chain, which the binner does not always link + * reliably. Denser tile counts fall back to smaller blocks, down to + * the 32-byte minimum which always fits. + */ + if (tile_state_aligned + 256 * tile_count <= vc4->bin_alloc_size) { + exec->tile_alloc_stride = 256; + init_block = VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_256; + } else if (tile_state_aligned + 128 * tile_count <= vc4->bin_alloc_size) { + exec->tile_alloc_stride = 128; + init_block = VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_128; + } else if (tile_state_aligned + 64 * tile_count <= vc4->bin_alloc_size) { + exec->tile_alloc_stride = 64; + init_block = VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_64; + } else { + exec->tile_alloc_stride = 32; + init_block = VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_32; + } *(uint8_t *)(validated + 14) = ((flags & ~(VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_MASK | VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_MASK)) | VC4_BIN_CONFIG_AUTO_INIT_TSDA | - VC4_SET_FIELD(VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_32, + VC4_SET_FIELD(init_block, VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE) | VC4_SET_FIELD(VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_128, VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE));