diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/gsp_sema_service.c | 39 |
1 files changed, 37 insertions, 2 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index 2eb9610..59e7262 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -8914,15 +8914,41 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf, ((st.remap_comp >> 16) & 0x3) : 0; u32 ndst = st.have_remap ? ((st.remap_comp >> 24) & 0x3) : 0; + u32 dst_x = st.have_remap ? + (st.remap_comp & 0x7) : 4; struct svc_memset_op *m = &ops[n_ops]; m->type = 0; m->dst = st.offset_out; + /* + * r367: the driver's own memset push + * (channel_utils.c) proves the + * encoding: LINE_LENGTH_IN is the + * fill SIZE IN BYTES, and + * SET_REMAP_COMPONENTS selects + * COMPONENT_SIZE ([17:16], 0..3 -> + * 1/2/3/4 bytes) and + * NUM_DST_COMPONENTS ([25:24], n+1 + * components). elem = + * (csz+1)*(ndst+1) is the pattern + * width; count must therefore be + * line_length/elem - the old + * count=line_length wrote + * elem x too much (r365: a 383620- + * byte memset wrote 1534480 bytes, + * clobbering the bytes after it). + * The value comes from the mapped + * constants: X<-CONST_A (4) and + * Y<-CONST_B (5); with two + * components the pattern is + * B:A 64-bit. + */ if (st.have_remap) m->value = ndst >= 1 ? (((u64)st.remap_b << 32) | st.remap_a) : - st.remap_b; + (dst_x == 5 ? st.remap_b : + st.remap_a); else /* * r357: a fill-shaped transfer @@ -8952,7 +8978,16 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf, m->value = 0; m->elem = st.have_remap ? (csz + 1) * (ndst + 1) : 1; - m->count = st.line_length; + if (m->elem > 1 && + st.line_length % m->elem) { + /* not pattern-divisible: exact + * byte count wins */ + m->elem = 1; + m->count = st.line_length; + } else { + m->count = st.line_length / + m->elem; + } m->phys = DMA_DST_TYPE_PHYSICAL(dma); m->aperture = st.have_dst_mode ? st.dst_phys_mode : CE_APERTURE_VID; |
