<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>
  <body>
    <p><br>
    </p>
    <div class="moz-cite-prefix">On 2021-04-12 1:44 p.m., Christian
      König wrote:<br>
    </div>
    <blockquote type="cite" cite="mid:cd94e02c-11c8-0198-ab70-0ceee54d437b@amd.com">
      
      <br>
      Am 12.04.21 um 19:27 schrieb Andrey Grodzovsky:<br>
      <blockquote type="cite" cite="mid:80713dbe-411c-d79b-34ba-b67bc3a50dc5@amd.com">
        <div class="moz-cite-prefix">On 2021-04-10 1:34 p.m., Christian
          König wrote:<br>
        </div>
        <blockquote type="cite" cite="mid:b6a24d3f-4fe6-c642-b478-36e386aa906d@gmail.com">Hi
          Andrey, <br>
          <br>
          Am 09.04.21 um 20:18 schrieb Andrey Grodzovsky: <br>
          <blockquote type="cite">[SNIP] <br>
            <blockquote type="cite">
              <blockquote type="cite"> <br>
                If we use a list and a flag called 'emit_allowed' under
                a lock such that in amdgpu_fence_emit we lock the list,
                check the flag and if true add the new HW fence to list
                and proceed to HW emition as normal, otherwise return
                with -ENODEV. In amdgpu_pci_remove we take the lock, set
                the flag to false, and then iterate the list and force
                signal it. Will this not prevent any new HW fence
                creation from now on from any place trying to do so ? <br>
              </blockquote>
              <br>
              Way to much overhead. The fence processing is
              intentionally lock free to avoid cache line bouncing
              because the IRQ can move from CPU to CPU. <br>
              <br>
              We need something which at least the processing of fences
              in the interrupt handler doesn't affect at all. <br>
            </blockquote>
            <br>
            <br>
            As far as I see in the code, amdgpu_fence_emit is only
            called from task context. Also, we can skip this list I
            proposed and just use amdgpu_fence_driver_force_completion
            for each ring to signal all created HW fences. <br>
          </blockquote>
          <br>
          Ah, wait a second this gave me another idea. <br>
          <br>
          See amdgpu_fence_driver_force_completion(): <br>
          <br>
          amdgpu_fence_write(ring, ring->fence_drv.sync_seq); <br>
          <br>
          If we change that to something like: <br>
          <br>
          amdgpu_fence_write(ring, ring->fence_drv.sync_seq +
          0x3FFFFFFF); <br>
          <br>
          Not only the currently submitted, but also the next 0x3FFFFFFF
          fences will be considered signaled. <br>
          <br>
          This basically solves out problem of making sure that new
          fences are also signaled without any additional overhead
          whatsoever.</blockquote>
        <p><br>
        </p>
        <p>Problem with this is that the act of setting the sync_seq to
          some MAX value alone is not enough, you actually have to call
          amdgpu_fence_process to iterate and signal the fences
          currently stored in ring->fence_drv.fences array and to
          guarantee that once you done your signalling no more HW fences
          will be added to that array anymore. I was thinking to do
          something like bellow:</p>
      </blockquote>
      <br>
      Well we could implement the is_signaled callback once more, but
      I'm not sure if that is a good idea.<br>
    </blockquote>
    <p><br>
    </p>
    <p>This indeed could save the explicit signaling I am doing bellow
      but I also set an error code there which might be helpful to
      propagate to users</p>
    <p><br>
    </p>
    <blockquote type="cite" cite="mid:cd94e02c-11c8-0198-ab70-0ceee54d437b@amd.com"> <br>
      <blockquote type="cite" cite="mid:80713dbe-411c-d79b-34ba-b67bc3a50dc5@amd.com">
        <p>amdgpu_fence_emit()</p>
        <p>{</p>
        <p>    dma_fence_init(fence);<br>
        </p>
        <p>    srcu_read_lock(amdgpu_unplug_srcu)</p>
        <p>    if (!adev->unplug)) {</p>
        <p>        seq = ++ring->fence_drv.sync_seq;<br>
                  emit_fence(fence);</p>
        <p>        <b>/* We can't wait forever as the HW might be gone
            at any point*/</b><b><br>
                   dma_fence_wait_timeout(old_fence, 5S);</b><br>
        </p>
      </blockquote>
      <br>
      You can pretty much ignore this wait here. It is only as a last
      resort so that we never overwrite the ring buffers.<br>
    </blockquote>
    <p><br>
    </p>
    <p>If device is present how can I ignore this ?</p>
    <p><br>
    </p>
    <blockquote type="cite" cite="mid:cd94e02c-11c8-0198-ab70-0ceee54d437b@amd.com"> <br>
      But it should not have a timeout as far as I can see.<br>
    </blockquote>
    <p><br>
    </p>
    <p>Without timeout wait the who approach falls apart as I can't call
      srcu_synchronize on this scope because once device is physically
      gone the wait here will be forever</p>
    <p><br>
    </p>
    <blockquote type="cite" cite="mid:cd94e02c-11c8-0198-ab70-0ceee54d437b@amd.com"> <br>
      <blockquote type="cite" cite="mid:80713dbe-411c-d79b-34ba-b67bc3a50dc5@amd.com">
        <p>         ring->fence_drv.fences[seq &
          ring->fence_drv.num_fences_mask] = fence;<br>
        </p>
        <p>    } else {</p>
        <p>        dma_fence_set_error(fence, -ENODEV);<br>
                  DMA_fence_signal(fence)    <br>
        </p>
        <p>    }   <br>
        </p>
        <p>    srcu_read_unlock(amdgpu_unplug_srcu)<br>
              return fence;<br>
        </p>
        <p>}</p>
        <p>amdgpu_pci_remove <br>
        </p>
        <p>{</p>
        <p>    adev->unplug = true;<br>
              synchronize_srcu(amdgpu_unplug_srcu) <br>
        </p>
      </blockquote>
      <br>
      Well that is just duplicating what drm_dev_unplug() should be
      doing on a different level.<br>
    </blockquote>
    <p><br>
    </p>
    <p>drm_dev_unplug is on a much wider scope, for everything in the
      device including 'flushing' in flight IOCTLs, this deals
      specifically with the issue of force signalling HW fences</p>
    <p>Andrey</p>
    <p><br>
    </p>
    <blockquote type="cite" cite="mid:cd94e02c-11c8-0198-ab70-0ceee54d437b@amd.com"> <br>
      Christian.<br>
      <br>
      <blockquote type="cite" cite="mid:80713dbe-411c-d79b-34ba-b67bc3a50dc5@amd.com">
        <p>    /* Past this point no more fence are submitted to HW ring
          and hence we can safely call force signal on all that are
          currently there. <br>
               * Any subsequently created  HW fences will be returned
          signaled with an error code right away <br>
               */<br>
        </p>
        <p>    for_each_ring(adev)<br>
                  amdgpu_fence_process(ring)</p>
        <p>    drm_dev_unplug(dev);<br>
              Stop schedulers<br>
              cancel_sync(all timers and queued works);<br>
              hw_fini<br>
              unmap_mmio<br>
        </p>
        <p>}</p>
        <p><br>
        </p>
        <p>Andrey</p>
        <p><br>
        </p>
        <blockquote type="cite" cite="mid:b6a24d3f-4fe6-c642-b478-36e386aa906d@gmail.com"> <br>
          <br>
          <blockquote type="cite"> <br>
            <blockquote type="cite">
              <blockquote type="cite">
                <blockquote type="cite"> <br>
                  Alternatively grabbing the reset write side and
                  stopping and then restarting the scheduler could work
                  as well. <br>
                  <br>
                  Christian. <br>
                </blockquote>
                <br>
                <br>
                I didn't get the above and I don't see why I need to
                reuse the GPU reset rw_lock. I rely on the SRCU unplug
                flag for unplug. Also, not clear to me why are we
                focusing on the scheduler threads, any code patch to
                generate HW fences should be covered, so any code
                leading to amdgpu_fence_emit needs to be taken into
                account such as, direct IB submissions, VM flushes e.t.c
                <br>
              </blockquote>
              <br>
              You need to work together with the reset lock anyway,
              cause a hotplug could run at the same time as a reset. <br>
            </blockquote>
            <br>
            <br>
            For going my way indeed now I see now that I have to take
            reset write side lock during HW fences signalling in order
            to protect against scheduler/HW fences detachment and
            reattachment during schedulers stop/restart. But if we go
            with your approach  then calling drm_dev_unplug and scoping
            amdgpu_job_timeout with drm_dev_enter/exit should be enough
            to prevent any concurrent GPU resets during unplug. In fact
            I already do it anyway - <a class="moz-txt-link-freetext" href="https://nam11.safelinks.protection.outlook.com/?url=https:%2F%2Fcgit.freedesktop.org%2F~agrodzov%2Flinux%2Fcommit%2F%3Fh%3Ddrm-misc-next%26id%3Def0ea4dd29ef44d2649c5eda16c8f4869acc36b1&amp;data=04%7C01%7Candrey.grodzovsky%40amd.com%7Ceefa9c90ed8c405ec3b708d8fc46daaa%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637536728550884740%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=UiNaJE%2BH45iYmbwSDnMSKZS5z0iak0fNlbbfYqKS2Jo%3D&amp;reserved=0" moz-do-not-send="true">https://nam11.safelinks.protection.outlook.com/?url=https:%2F%2Fcgit.freedesktop.org%2F~agrodzov%2Flinux%2Fcommit%2F%3Fh%3Ddrm-misc-next%26id%3Def0ea4dd29ef44d2649c5eda16c8f4869acc36b1&amp;data=04%7C01%7Candrey.grodzovsky%40amd.com%7Ceefa9c90ed8c405ec3b708d8fc46daaa%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637536728550884740%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=UiNaJE%2BH45iYmbwSDnMSKZS5z0iak0fNlbbfYqKS2Jo%3D&amp;reserved=0</a><br>
          </blockquote>
          <br>
          Yes, good point as well. <br>
          <br>
          Christian. <br>
          <br>
          <blockquote type="cite"> <br>
            Andrey <br>
            <br>
            <br>
            <blockquote type="cite"> <br>
              <br>
              Christian. <br>
              <br>
              <blockquote type="cite"> <br>
                Andrey <br>
                <br>
                <br>
                <blockquote type="cite"> <br>
                  <blockquote type="cite"> <br>
                    Christian. <br>
                    <br>
                    <blockquote type="cite"> <br>
                      Andrey <br>
                      <br>
                      <br>
                      <blockquote type="cite"> <br>
                        <blockquote type="cite">Andrey <br>
                          <br>
                          <br>
                        </blockquote>
                        <br>
                      </blockquote>
                    </blockquote>
                    <br>
                  </blockquote>
                  <br>
                </blockquote>
              </blockquote>
              <br>
            </blockquote>
          </blockquote>
          <br>
        </blockquote>
      </blockquote>
      <br>
    </blockquote>
  </body>
</html>