diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/gsp_display_engine.c | 51 |
1 files changed, 49 insertions, 2 deletions
diff --git a/kernel/gsp_display_engine.c b/kernel/gsp_display_engine.c index 5109245..426d6a1 100644 --- a/kernel/gsp_display_engine.c +++ b/kernel/gsp_display_engine.c @@ -439,6 +439,7 @@ static int gsp_disp_ctxdma_pa(struct nv_vgpu_device *vgpu, u32 handle, if (have_im) { u64 e; + const char *im_src = "fb"; if (!disp.ibuf) return -ENOMEM; @@ -446,6 +447,52 @@ static int gsp_disp_ctxdma_pa(struct nv_vgpu_device *vgpu, u32 handle, GSP_DISP_INST_OBJ_END)) return -ENOENT; + /* + * The RM may write vidmem through a coherent CPU mapping + * instead of the BAR1 aperture, in which case the block lands + * at the same address in guest RAM rather than in the FB + * shadow. If the shadow copy is empty, retry through + * vfio_dma_rw before giving up. + */ + if (im_space == 2) { + u64 nz = 0; + + for (e = 0; e < GSP_DISP_INST_HASH_END; e += 8) { + u32 a = *(u32 *)(disp.ibuf + e); + u32 b = *(u32 *)(disp.ibuf + e + 4); + + if (a || b) + nz++; + } + if (!nz) { + u8 *tmp = kmalloc(GSP_DISP_INST_OBJ_END, + GFP_KERNEL); + + if (tmp) { + if (vfio_dma_rw(&vgpu->vfio_dev, im_pa, + tmp, + GSP_DISP_INST_OBJ_END, + false) == 0) { + for (e = 0; + e < GSP_DISP_INST_HASH_END; + e += 8) { + u32 a = *(u32 *)(tmp + e); + u32 b = *(u32 *)(tmp + e + 4); + + if (a || b) + nz++; + } + if (nz) { + memcpy(disp.ibuf, tmp, + GSP_DISP_INST_OBJ_END); + im_src = "ram"; + } + } + kfree(tmp); + } + } + } + if (gsp_disp_dbg && disp.im_logs < 8) { u32 nz = 0, shown = 0; @@ -463,8 +510,8 @@ static int gsp_disp_ctxdma_pa(struct nv_vgpu_device *vgpu, u32 handle, } } disp.im_logs++; - pr_info("inst mem pa=0x%llx space=%u handle=0x%x hash_nz=%u\n", - im_pa, im_space, handle, nz); + pr_info("inst mem pa=0x%llx space=%u src=%s handle=0x%x hash_nz=%u\n", + im_pa, im_space, im_src, handle, nz); /* * The announced block may not be where the RM's writes |
