};
 #define to_intel_bo(x) container_of(x, struct drm_i915_gem_object, base)
 
-void i915_gem_track_fb(struct drm_i915_gem_object *old,
-                      struct drm_i915_gem_object *new,
-                      unsigned frontbuffer_bits);
+/*
+ * Optimised SGL iterator for GEM objects
+ */
+static __always_inline struct sgt_iter {
+       struct scatterlist *sgp;
+       union {
+               unsigned long pfn;
+               dma_addr_t dma;
+       };
+       unsigned int curr;
+       unsigned int max;
+} __sgt_iter(struct scatterlist *sgl, bool dma) {
+       struct sgt_iter s = { .sgp = sgl };
+
+       if (s.sgp) {
+               s.max = s.curr = s.sgp->offset;
+               s.max += s.sgp->length;
+               if (dma)
+                       s.dma = sg_dma_address(s.sgp);
+               else
+                       s.pfn = page_to_pfn(sg_page(s.sgp));
+       }
+
+       return s;
+}
+
+/**
+ * for_each_sgt_dma - iterate over the DMA addresses of the given sg_table
+ * @__dmap:    DMA address (output)
+ * @__iter:    'struct sgt_iter' (iterator state, internal)
+ * @__sgt:     sg_table to iterate over (input)
+ */
+#define for_each_sgt_dma(__dmap, __iter, __sgt)                                \
+       for ((__iter) = __sgt_iter((__sgt)->sgl, true);                 \
+            ((__dmap) = (__iter).dma + (__iter).curr);                 \
+            (((__iter).curr += PAGE_SIZE) < (__iter).max) ||           \
+            ((__iter) = __sgt_iter(sg_next((__iter).sgp), true), 0))
+
+/**
+ * for_each_sgt_page - iterate over the pages of the given sg_table
+ * @__pp:      page pointer (output)
+ * @__iter:    'struct sgt_iter' (iterator state, internal)
+ * @__sgt:     sg_table to iterate over (input)
+ */
+#define for_each_sgt_page(__pp, __iter, __sgt)                         \
+       for ((__iter) = __sgt_iter((__sgt)->sgl, false);                \
+            ((__pp) = (__iter).pfn == 0 ? NULL :                       \
+             pfn_to_page((__iter).pfn + ((__iter).curr >> PAGE_SHIFT))); \
+            (((__iter).curr += PAGE_SIZE) < (__iter).max) ||           \
+            ((__iter) = __sgt_iter(sg_next((__iter).sgp), false), 0))
 
 /**
  * Request queue structure.
                         struct drm_mode_create_dumb *args);
 int i915_gem_mmap_gtt(struct drm_file *file_priv, struct drm_device *dev,
                      uint32_t handle, uint64_t *offset);
+
+void i915_gem_track_fb(struct drm_i915_gem_object *old,
+                      struct drm_i915_gem_object *new,
+                      unsigned frontbuffer_bits);
+
 /**
  * Returns true if seq1 is later than seq2.
  */
 
 static void
 i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj)
 {
-       struct sg_page_iter sg_iter;
+       struct sgt_iter sgt_iter;
+       struct page *page;
        int ret;
 
        BUG_ON(obj->madv == __I915_MADV_PURGED);
        if (obj->madv == I915_MADV_DONTNEED)
                obj->dirty = 0;
 
-       for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) {
-               struct page *page = sg_page_iter_page(&sg_iter);
-
+       for_each_sgt_page(page, sgt_iter, obj->pages) {
                if (obj->dirty)
                        set_page_dirty(page);
 
        struct address_space *mapping;
        struct sg_table *st;
        struct scatterlist *sg;
-       struct sg_page_iter sg_iter;
+       struct sgt_iter sgt_iter;
        struct page *page;
        unsigned long last_pfn = 0;     /* suppress gcc warning */
        int ret;
 
 err_pages:
        sg_mark_end(sg);
-       for_each_sg_page(st->sgl, &sg_iter, st->nents, 0)
-               put_page(sg_page_iter_page(&sg_iter));
+       for_each_sgt_page(page, sgt_iter, st)
+               put_page(page);
        sg_free_table(st);
        kfree(st);
 
 {
        unsigned long n_pages = obj->base.size >> PAGE_SHIFT;
        struct sg_table *sgt = obj->pages;
-       struct sg_page_iter sg_iter;
+       struct sgt_iter sgt_iter;
+       struct page *page;
        struct page *stack_pages[32];
        struct page **pages = stack_pages;
        unsigned long i = 0;
                        return NULL;
        }
 
-       for_each_sg_page(sgt->sgl, &sg_iter, sgt->nents, 0)
-               pages[i++] = sg_page_iter_page(&sg_iter);
+       for_each_sgt_page(page, sgt_iter, sgt)
+               pages[i++] = page;
 
        /* Check that we have the expected number of pages */
        GEM_BUG_ON(i != n_pages);
 
 void
 i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj)
 {
-       struct sg_page_iter sg_iter;
+       struct sgt_iter sgt_iter;
+       struct page *page;
        int i;
 
        if (obj->bit_17 == NULL)
                return;
 
        i = 0;
-       for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) {
-               struct page *page = sg_page_iter_page(&sg_iter);
+       for_each_sgt_page(page, sgt_iter, obj->pages) {
                char new_bit_17 = page_to_phys(page) >> 17;
                if ((new_bit_17 & 0x1) !=
                    (test_bit(i, obj->bit_17) != 0)) {
 void
 i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj)
 {
-       struct sg_page_iter sg_iter;
+       struct sgt_iter sgt_iter;
+       struct page *page;
        int page_count = obj->base.size >> PAGE_SHIFT;
        int i;
 
        }
 
        i = 0;
-       for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) {
-               if (page_to_phys(sg_page_iter_page(&sg_iter)) & (1 << 17))
+
+       for_each_sgt_page(page, sgt_iter, obj->pages) {
+               if (page_to_phys(page) & (1 << 17))
                        __set_bit(i, obj->bit_17);
                else
                        __clear_bit(i, obj->bit_17);
 
                                      enum i915_cache_level cache_level, u32 flags)
 {
        struct i915_hw_ppgtt *ppgtt = i915_vm_to_ppgtt(vm);
-       gen6_pte_t *pt_vaddr;
        unsigned first_entry = start >> PAGE_SHIFT;
        unsigned act_pt = first_entry / GEN6_PTES;
        unsigned act_pte = first_entry % GEN6_PTES;
-       struct sg_page_iter sg_iter;
+       gen6_pte_t *pt_vaddr = NULL;
+       struct sgt_iter sgt_iter;
+       dma_addr_t addr;
 
-       pt_vaddr = NULL;
-       for_each_sg_page(pages->sgl, &sg_iter, pages->nents, 0) {
+       for_each_sgt_dma(addr, sgt_iter, pages) {
                if (pt_vaddr == NULL)
                        pt_vaddr = kmap_px(ppgtt->pd.page_table[act_pt]);
 
                pt_vaddr[act_pte] =
-                       vm->pte_encode(sg_page_iter_dma_address(&sg_iter),
-                                      cache_level, true, flags);
+                       vm->pte_encode(addr, cache_level, true, flags);
 
                if (++act_pte == GEN6_PTES) {
                        kunmap_px(ppgtt, pt_vaddr);
                        act_pte = 0;
                }
        }
+
        if (pt_vaddr)
                kunmap_px(ppgtt, pt_vaddr);
 }
 {
        struct drm_i915_private *dev_priv = to_i915(vm->dev);
        struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
-       unsigned first_entry = start >> PAGE_SHIFT;
-       gen8_pte_t __iomem *gtt_entries =
-               (gen8_pte_t __iomem *)ggtt->gsm + first_entry;
-       int i = 0;
-       struct sg_page_iter sg_iter;
-       dma_addr_t addr = 0; /* shut up gcc */
+       struct sgt_iter sgt_iter;
+       gen8_pte_t __iomem *gtt_entries;
+       gen8_pte_t gtt_entry;
+       dma_addr_t addr;
        int rpm_atomic_seq;
+       int i = 0;
 
        rpm_atomic_seq = assert_rpm_atomic_begin(dev_priv);
 
-       for_each_sg_page(st->sgl, &sg_iter, st->nents, 0) {
-               addr = sg_dma_address(sg_iter.sg) +
-                       (sg_iter.sg_pgoffset << PAGE_SHIFT);
-               gen8_set_pte(>t_entries[i],
-                            gen8_pte_encode(addr, level, true));
-               i++;
+       gtt_entries = (gen8_pte_t __iomem *)ggtt->gsm + (start >> PAGE_SHIFT);
+
+       for_each_sgt_dma(addr, sgt_iter, st) {
+               gtt_entry = gen8_pte_encode(addr, level, true);
+               gen8_set_pte(>t_entries[i++], gtt_entry);
        }
 
        /*
         * hardware should work, we must keep this posting read for paranoia.
         */
        if (i != 0)
-               WARN_ON(readq(>t_entries[i-1])
-                       != gen8_pte_encode(addr, level, true));
+               WARN_ON(readq(>t_entries[i-1]) != gtt_entry);
 
        /* This next bit makes the above posting read even more important. We
         * want to flush the TLBs only after we're certain all the PTE updates
 {
        struct drm_i915_private *dev_priv = to_i915(vm->dev);
        struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
-       unsigned first_entry = start >> PAGE_SHIFT;
-       gen6_pte_t __iomem *gtt_entries =
-               (gen6_pte_t __iomem *)ggtt->gsm + first_entry;
-       int i = 0;
-       struct sg_page_iter sg_iter;
-       dma_addr_t addr = 0;
+       struct sgt_iter sgt_iter;
+       gen6_pte_t __iomem *gtt_entries;
+       gen6_pte_t gtt_entry;
+       dma_addr_t addr;
        int rpm_atomic_seq;
+       int i = 0;
 
        rpm_atomic_seq = assert_rpm_atomic_begin(dev_priv);
 
-       for_each_sg_page(st->sgl, &sg_iter, st->nents, 0) {
-               addr = sg_page_iter_dma_address(&sg_iter);
-               iowrite32(vm->pte_encode(addr, level, true, flags), >t_entries[i]);
-               i++;
+       gtt_entries = (gen6_pte_t __iomem *)ggtt->gsm + (start >> PAGE_SHIFT);
+
+       for_each_sgt_dma(addr, sgt_iter, st) {
+               gtt_entry = vm->pte_encode(addr, level, true, flags);
+               iowrite32(gtt_entry, >t_entries[i++]);
        }
 
        /* XXX: This serves as a posting read to make sure that the PTE has
         * of NUMA access patterns. Therefore, even with the way we assume
         * hardware should work, we must keep this posting read for paranoia.
         */
-       if (i != 0) {
-               unsigned long gtt = readl(>t_entries[i-1]);
-               WARN_ON(gtt != vm->pte_encode(addr, level, true, flags));
-       }
+       if (i != 0)
+               WARN_ON(readl(>t_entries[i-1]) != gtt_entry);
 
        /* This next bit makes the above posting read even more important. We
         * want to flush the TLBs only after we're certain all the PTE updates
 intel_rotate_fb_obj_pages(struct intel_rotation_info *rot_info,
                          struct drm_i915_gem_object *obj)
 {
+       const size_t n_pages = obj->base.size / PAGE_SIZE;
        unsigned int size_pages = rot_info->plane[0].width * rot_info->plane[0].height;
        unsigned int size_pages_uv;
-       struct sg_page_iter sg_iter;
+       struct sgt_iter sgt_iter;
+       dma_addr_t dma_addr;
        unsigned long i;
        dma_addr_t *page_addr_list;
        struct sg_table *st;
        int ret = -ENOMEM;
 
        /* Allocate a temporary list of source pages for random access. */
-       page_addr_list = drm_malloc_gfp(obj->base.size / PAGE_SIZE,
+       page_addr_list = drm_malloc_gfp(n_pages,
                                        sizeof(dma_addr_t),
                                        GFP_TEMPORARY);
        if (!page_addr_list)
 
        /* Populate source page list from the object. */
        i = 0;
-       for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) {
-               page_addr_list[i] = sg_page_iter_dma_address(&sg_iter);
-               i++;
-       }
+       for_each_sgt_dma(dma_addr, sgt_iter, obj->pages)
+               page_addr_list[i++] = dma_addr;
 
+       GEM_BUG_ON(i != n_pages);
        st->nents = 0;
        sg = st->sgl;
 
 
 static void
 i915_gem_userptr_put_pages(struct drm_i915_gem_object *obj)
 {
-       struct sg_page_iter sg_iter;
+       struct sgt_iter sgt_iter;
+       struct page *page;
 
        BUG_ON(obj->userptr.work != NULL);
        __i915_gem_userptr_set_active(obj, false);
 
        i915_gem_gtt_finish_object(obj);
 
-       for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) {
-               struct page *page = sg_page_iter_page(&sg_iter);
-
+       for_each_sgt_page(page, sgt_iter, obj->pages) {
                if (obj->dirty)
                        set_page_dirty(page);