• Chris Wilson's avatar
    drm/i915: Prevent negative relocation deltas from wrapping · d23db88c
    Chris Wilson authored
    This is pure evil. Userspace, I'm looking at you SNA, repacks batch
    buffers on the fly after generation as they are being passed to the
    kernel for execution. These batches also contain self-referenced
    relocations as a single buffer encompasses the state commands, kernels,
    vertices and sampler. During generation the buffers are placed at known
    offsets within the full batch, and then the relocation deltas (as passed
    to the kernel) are tweaked as the batch is repacked into a smaller buffer.
    This means that userspace is passing negative relocations deltas, which
    subsequently wrap to large values if the batch is at a low address. The
    GPU hangs when it then tries to use the large value as a base for its
    address offsets, rather than wrapping back to the real value (as one
    would hope). As the GPU uses positive offsets from the base, we can
    treat the relocation address as the minimum address read by the GPU.
    For the upper bound, we trust that userspace will not read beyond the
    end of the buffer.
    
    So, how do we fix negative relocations from wrapping? We can either
    check that every relocation looks valid when we write it, and then
    position each object such that we prevent the offset wraparound, or we
    just special-case the self-referential behaviour of SNA and force all
    batches to be above 256k. Daniel prefers the latter approach.
    
    This fixes a GPU hang when it tries to use an address (relocation +
    offset) greater than the GTT size. The issue would occur quite easily
    with full-ppgtt as each fd gets its own VM space, so low offsets would
    often be handed out. However, with the rearrangement of the low GTT due
    to capturing the BIOS framebuffer, it is already affecting kernels 3.15
    onwards. I think only IVB+ is susceptible to this bug, but the workaround
    should only kick in rarely, so it seems sensible to always apply it.
    
    v3: Use a bias for batch buffers to prevent small negative delta relocations
    from wrapping.
    
    v4 from Daniel:
    - s/BIAS/BATCH_OFFSET_BIAS/
    - Extract eb_vma_misplaced/i915_vma_misplaced since the conditions
      were growing rather cumbersome.
    - Add a comment to eb_get_batch explaining why we do this.
    - Apply the batch offset bias everywhere but mention that we've only
      observed it on gen7 gpus.
    - Drop PIN_OFFSET_FIX for now, that slipped in from a feature patch.
    
    v5: Add static to eb_get_batch, spotted by 0-day tester.
    
    Testcase: igt/gem_bad_reloc
    Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=78533
    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> (v3)
    Cc: stable@vger.kernel.org
    Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
    d23db88c
i915_gem_gtt.c 56.6 KB