Commit 255fc1703e42 ("drm/i915/gem: Calculate object page offset for partial memory mapping") introduced a new offset that affects r.sgt.curr value. This field is used in remap_sg() function, in set_pte_at() call and changing its value causes page table entry to also be affected (see set_ptes() description). Example: 1) upon entering remap_sg() r.sgt.curr could have already been changed to a value equal to or greater than r.sgt.max, 2) set_pte_at() uses r.sgt.curr to map a page entry from another segment to the current one, 3) r->sgt pointer is moved to the next entry returned from __sg_iter() only once, 3) the memory of the mismapped page might become unavailabe (accessing some addresses causes -EFAULT). This patch moves current r->sgt pointer as many segments, as initial r.sgt.curr is still larger than r.sgt.max. Signed-off-by: Krzysztof Karas <krzysztof.karas@xxxxxxxxx> --- drivers/gpu/drm/i915/i915_mm.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_mm.c b/drivers/gpu/drm/i915/i915_mm.c index f5c97a620962..9a140840214b 100644 --- a/drivers/gpu/drm/i915/i915_mm.c +++ b/drivers/gpu/drm/i915/i915_mm.c @@ -51,10 +51,22 @@ static inline unsigned long sgt_pfn(const struct remap_pfn *r) static int remap_sg(pte_t *pte, unsigned long addr, void *data) { struct remap_pfn *r = data; + unsigned int sgt_offset; if (GEM_WARN_ON(!r->sgt.sgp)) return -EINVAL; + if (r->sgt.curr == r->sgt.max) { + r->sgt = __sgt_iter(__sg_next(r->sgt.sgp), use_dma(r->iobase)); + } else if (r->sgt.curr > r->sgt.max) { + sgt_offset = r->sgt.curr; + while (sgt_offset >= r->sgt.max) { + sgt_offset -= r->sgt.max; + r->sgt = __sgt_iter(__sg_next(r->sgt.sgp), use_dma(r->iobase)); + } + r->sgt.curr = sgt_offset; + } + /* Special PTE are not associated with any struct page */ set_pte_at(r->mm, addr, pte, pte_mkspecial(pfn_pte(sgt_pfn(r), r->prot))); -- 2.43.0