.mmap = NULL,
 };
 
-static int expose_firmware_sysfs(struct intel_gvt *gvt)
+static int mmio_snapshot_handler(struct intel_gvt *gvt, u32 offset, void *data)
 {
        struct drm_i915_private *dev_priv = gvt->dev_priv;
+
+       *(u32 *)(data + offset) = I915_READ_NOTRACE(_MMIO(offset));
+       return 0;
+}
+
+static int expose_firmware_sysfs(struct intel_gvt *gvt)
+{
        struct intel_gvt_device_info *info = &gvt->device_info;
        struct pci_dev *pdev = gvt->dev_priv->drm.pdev;
-       struct intel_gvt_mmio_info *e;
-       struct gvt_mmio_block *block = gvt->mmio.mmio_block;
-       int num = gvt->mmio.num_mmio_block;
        struct gvt_firmware_header *h;
        void *firmware;
        void *p;
        unsigned long size, crc32_start;
-       int i, j;
-       int ret;
+       int i, ret;
 
        size = sizeof(*h) + info->mmio_size + info->cfg_space_size;
        firmware = vzalloc(size);
 
        p = firmware + h->mmio_offset;
 
-       hash_for_each(gvt->mmio.mmio_info_table, i, e, node)
-               *(u32 *)(p + e->offset) = I915_READ_NOTRACE(_MMIO(e->offset));
-
-       for (i = 0; i < num; i++, block++) {
-               for (j = 0; j < block->size; j += 4)
-                       *(u32 *)(p + INTEL_GVT_MMIO_OFFSET(block->offset) + j) =
-                               I915_READ_NOTRACE(_MMIO(INTEL_GVT_MMIO_OFFSET(
-                                                       block->offset) + j));
-       }
+       /* Take a snapshot of hw mmio registers. */
+       intel_gvt_for_each_tracked_mmio(gvt, mmio_snapshot_handler, p);
 
        memcpy(gvt->firmware.mmio, p, info->mmio_size);
 
 
        return ret;
 }
 
+/**
+ * intel_gvt_for_each_tracked_mmio - iterate each tracked mmio
+ * @gvt: a GVT device
+ * @handler: the handler
+ * @data: private data given to handler
+ *
+ * Returns:
+ * Zero on success, negative error code if failed.
+ */
+int intel_gvt_for_each_tracked_mmio(struct intel_gvt *gvt,
+       int (*handler)(struct intel_gvt *gvt, u32 offset, void *data),
+       void *data)
+{
+       struct gvt_mmio_block *block = gvt->mmio.mmio_block;
+       struct intel_gvt_mmio_info *e;
+       int i, j, ret;
+
+       hash_for_each(gvt->mmio.mmio_info_table, i, e, node) {
+               ret = handler(gvt, e->offset, data);
+               if (ret)
+                       return ret;
+       }
+
+       for (i = 0; i < gvt->mmio.num_mmio_block; i++, block++) {
+               for (j = 0; j < block->size; j += 4) {
+                       ret = handler(gvt,
+                               INTEL_GVT_MMIO_OFFSET(block->offset) + j,
+                               data);
+                       if (ret)
+                               return ret;
+               }
+       }
+       return 0;
+}
 
 /**
  * intel_vgpu_default_mmio_read - default MMIO read handler
 
 
 int intel_gvt_setup_mmio_info(struct intel_gvt *gvt);
 void intel_gvt_clean_mmio_info(struct intel_gvt *gvt);
+int intel_gvt_for_each_tracked_mmio(struct intel_gvt *gvt,
+       int (*handler)(struct intel_gvt *gvt, u32 offset, void *data),
+       void *data);
+
 
 #define INTEL_GVT_MMIO_OFFSET(reg) ({ \
        typeof(reg) __reg = reg; \