<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Nov 2, 2016 at 9:43 AM, Chris Wilson <span dir="ltr"><<a href="mailto:chris@chris-wilson.co.uk" target="_blank">chris@chris-wilson.co.uk</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span>On Tue, Nov 01, 2016 at 03:35:13PM -0700, Jason Ekstrand wrote:<br>
> +static void<br>
> +write_reloc(const struct anv_device *device, void *p, uint64_t v)<br>
> +{<br>
> + unsigned reloc_size = 0;<br>
> + if (device->info.gen >= 8) {<br>
> + /* From the Broadwell PRM Vol. 2a, MI_LOAD_REGISTER_MEM::MemoryAd<wbr>dress:<br>
> + *<br>
> + * "This field specifies the address of the memory location where the<br>
> + * register value specified in the DWord above will read from. The<br>
> + * address specifies the DWord location of the data. Range =<br>
> + * GraphicsVirtualAddress[63:2] for a DWord register GraphicsAddress<br>
> + * [63:48] are ignored by the HW and assumed to be in correct<br>
> + * canonical form [63:48] == [47]."<br>
> + */<br>
<br>
</span>const int shift = 63 - 47; /* != 8 :) */<br><div><div class="m_708412035767053171h5"></div></div></blockquote><div><br></div><div>Drp... I'll use the const int. :-)<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div class="m_708412035767053171h5">
> + reloc_size = sizeof(uint64_t);<br>
> + *(uint64_t *)p = (((int64_t)v) << 8) >> 8;<br>
> + } else {<br>
> + reloc_size = sizeof(uint32_t);<br>
> + *(uint32_t *)p = v;<br>
> + }<br>
> +<br>
> + if (!device->info.has_llc)<br>
> + anv_clflush_range(p, reloc_size);<br>
> +}<br>
> +<br>
> +static void<br>
> +anv_reloc_list_apply(struct anv_reloc_list *list,<br>
> + struct anv_device *device, struct anv_bo *bo)<br>
> +{<br>
> + for (size_t i = 0; i < list->num_relocs; i++) {<br>
> + void *p = bo->map + list->relocs[i].offset;<br>
> +<br>
> + struct anv_bo *target_bo = list->reloc_bos[i];<br>
> + write_reloc(device, p, target_bo->offset + list->relocs[i].delta);<br>
> + list->relocs[i].presumed_offse<wbr>t = bo->offset;<br>
> + }<br>
> +}<br>
> +<br>
> +/**<br>
> + * This function applies the relocation for a command buffer and writes the<br>
> + * actual addresses into the buffers as per what we were told by the kernel on<br>
> + * the previous execbuf2 call. This should be safe to do because, for each<br>
> + * relocated address, we have two cases:<br>
> + *<br>
> + * 1) The target BO is inactive (as seen by the kernel). In this case, it is<br>
> + * not in use by the GPU so updating the address is 100% ok. It won't be<br>
> + * in-use by the GPU (from our context) again until the next execbuf2<br>
> + * happens. If the kernel decides to move it in the next execbuf2, it<br>
> + * will have to do the relocations itself, but that's ok because it should<br>
> + * have all of the information needed to do so.<br>
> + *<br>
> + * 2) The target BO is active (as seen by the kernel). In this case, it<br>
> + * hasn't moved since the last execbuffer2 call because GTT shuffling<br>
> + * *only* happens inside the execbuffer2 ioctl. Since the target BO<br>
> + * hasn't moved, our anv_bo::offset exactly matches the BO's GTT address<br>
> + * and the relocated value we are writing into the BO will be the same as<br>
> + * the value that is already there.<br>
> + *<br>
> + * There is also a possibility that the target BO is active but the exact<br>
> + * RENDER_SURFACE_STATE object we are writing the relocation into isn't in<br>
> + * use. In this case, the address currently in the RENDER_SURFACE_STATE<br>
> + * may be stale but it's still safe to write the relocation because that<br>
> + * particular RENDER_SURFACE_STATE object isn't in-use by the GPU and<br>
> + * won't be until the next execbuf2 call.<br>
> + *<br>
> + * By doing relocations on the CPU, we can tell the kernel that it doesn't<br>
> + * need to bother. We want to do this because the surface state buffer is<br>
> + * used by every command buffer so, if the kernel does the relocations, it<br>
> + * will always be busy and the kernel will always stall. This is also<br>
> + * probably the fastest mechanism for doing relocations since the kernel would<br>
> + * have to make a full copy of all the relocations lists.<br>
> + */<br>
> +static void<br>
> +relocate_cmd_buffer(struct anv_cmd_buffer *cmd_buffer)<br>
> +{<br>
> + for (uint32_t i = 0; i < cmd_buffer->execbuf2.bo_count; i++) {<br>
> + if (cmd_buffer->execbuf2.bos[i]-><wbr>offset == (uint64_t)-1)<br>
> + return;<br>
> + }<br>
<br>
</div></div>Note you still have to make sure the reloc.presumed_offset matches the<br>
value used to compute the contents of the buffer. Old relocations will<br>
retain their value from the previous pass, new allocations will have<br>
presumed_offset = 0 and hopefully the content will be delta. (Otherwise<br>
you run into trouble if the kernel places the buffer at 0, it will then<br>
skip the relocations pointing to it.)<br></blockquote><div><br></div>So, I *thought* we were doing this correctly, but I think the current code is a bit on the busted side. I'm going to be sending out a v3 that has some general relocation fixes as well as more comments (along the line of what you said above)<br><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
That deserves a comment (if only to contrast the two paths).<br>
<span><br>
> + anv_reloc_list_apply(&cmd_buf<wbr>fer->surface_relocs,<br>
> + cmd_buffer->device,<br>
> + &cmd_buffer->device-><a href="http://surface_state_block_pool.bo" rel="noreferrer" target="_blank">surface_s<wbr>tate_block_pool.bo</a>);<br>
> +<br>
> + struct anv_batch_bo **bbo;<br>
> + u_vector_foreach(bbo, &cmd_buffer->seen_bbos) {<br>
> + anv_reloc_list_apply(&(*bbo)-><wbr>relocs,<br>
> + cmd_buffer->device, &(*bbo)->bo);<br>
> + }<br>
> +<br>
> + for (uint32_t i = 0; i < cmd_buffer->execbuf2.bo_count; i++) {<br>
> + struct anv_bo *bo = cmd_buffer->execbuf2.bos[i];<br>
> +<br>
> + cmd_buffer->execbuf2.objects[i<wbr>].offset = bo->offset;<br>
<br>
</span>/* bo->offset = last execobj.offset */<br>
<br>
*reloc.offset = bo->offset + delta;<br>
reloc.presumed_offset = bo->offset;<br>
execobj.offset = bo->offset;<br>
<br>
Looks good.<br>
<span class="m_708412035767053171HOEnZb"><font color="#888888">-Chris<br>
<br>
--<br>
Chris Wilson, Intel Open Source Technology Centre<br>
</font></span></blockquote></div><br></div></div>