Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/etnaviv: replace MMU flush marker with flush sequence

If a MMU is shared between multiple GPUs, all of them need to flush their
TLBs, so a single marker that gets reset on the first flush won't do.
Replace the flush marker with a sequence number, so that it's possible to
check if the TLB is in sync with the current page table state for each GPU.

Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
Reviewed-by: Guido Günther <agx@sigxcpu.org>

+11 -8
+6 -4
drivers/gpu/drm/etnaviv/etnaviv_buffer.c
··· 315 315 u32 return_target, return_dwords; 316 316 u32 link_target, link_dwords; 317 317 bool switch_context = gpu->exec_state != exec_state; 318 + unsigned int new_flush_seq = READ_ONCE(gpu->mmu->flush_seq); 319 + bool need_flush = gpu->flush_seq != new_flush_seq; 318 320 319 321 lockdep_assert_held(&gpu->lock); 320 322 ··· 331 329 * need to append a mmu flush load state, followed by a new 332 330 * link to this buffer - a total of four additional words. 333 331 */ 334 - if (gpu->mmu->need_flush || switch_context) { 332 + if (need_flush || switch_context) { 335 333 u32 target, extra_dwords; 336 334 337 335 /* link command */ 338 336 extra_dwords = 1; 339 337 340 338 /* flush command */ 341 - if (gpu->mmu->need_flush) { 339 + if (need_flush) { 342 340 if (gpu->mmu->version == ETNAVIV_IOMMU_V1) 343 341 extra_dwords += 1; 344 342 else ··· 351 349 352 350 target = etnaviv_buffer_reserve(gpu, buffer, extra_dwords); 353 351 354 - if (gpu->mmu->need_flush) { 352 + if (need_flush) { 355 353 /* Add the MMU flush */ 356 354 if (gpu->mmu->version == ETNAVIV_IOMMU_V1) { 357 355 CMD_LOAD_STATE(buffer, VIVS_GL_FLUSH_MMU, ··· 371 369 SYNC_RECIPIENT_PE); 372 370 } 373 371 374 - gpu->mmu->need_flush = false; 372 + gpu->flush_seq = new_flush_seq; 375 373 } 376 374 377 375 if (switch_context) {
+1
drivers/gpu/drm/etnaviv/etnaviv_gpu.h
··· 137 137 int irq; 138 138 139 139 struct etnaviv_iommu *mmu; 140 + unsigned int flush_seq; 140 141 141 142 /* Power Control: */ 142 143 struct clk *clk_bus;
+3 -3
drivers/gpu/drm/etnaviv/etnaviv_mmu.c
··· 263 263 } 264 264 265 265 list_add_tail(&mapping->mmu_node, &mmu->mappings); 266 - mmu->need_flush = true; 266 + mmu->flush_seq++; 267 267 unlock: 268 268 mutex_unlock(&mmu->lock); 269 269 ··· 282 282 etnaviv_iommu_remove_mapping(mmu, mapping); 283 283 284 284 list_del(&mapping->mmu_node); 285 - mmu->need_flush = true; 285 + mmu->flush_seq++; 286 286 mutex_unlock(&mmu->lock); 287 287 } 288 288 ··· 369 369 return ret; 370 370 } 371 371 372 - mmu->need_flush = true; 372 + mmu->flush_seq++; 373 373 } 374 374 375 375 list_add_tail(&mapping->mmu_node, &mmu->mappings);
+1 -1
drivers/gpu/drm/etnaviv/etnaviv_mmu.h
··· 48 48 struct mutex lock; 49 49 struct list_head mappings; 50 50 struct drm_mm mm; 51 - bool need_flush; 51 + unsigned int flush_seq; 52 52 }; 53 53 54 54 struct etnaviv_gem_object;