diff --git a/xen/arch/x86/hvm/dm.c b/xen/arch/x86/hvm/dm.c
index f97478b..a92d5d7 100644
--- a/xen/arch/x86/hvm/dm.c
+++ b/xen/arch/x86/hvm/dm.c
@@ -288,6 +288,7 @@ static int inject_event(struct domain *d,
     return 0;
 }
 
+#define DMOP_op_mask 0xff
 static int dm_op(domid_t domid,
                  unsigned int nr_bufs,
                  xen_dm_op_buf_t bufs[])
@@ -315,10 +316,8 @@ static int dm_op(domid_t domid,
     }
 
     rc = -EINVAL;
-    if ( op.pad )
-        goto out;
 
-    switch ( op.op )
+    switch ( op.op & DMOP_op_mask )
     {
     case XEN_DMOP_create_ioreq_server:
     {
@@ -387,6 +386,10 @@ static int dm_op(domid_t domid,
     {
         const struct xen_dm_op_map_mem_type_to_ioreq_server *data =
             &op.u.map_mem_type_to_ioreq_server;
+        unsigned long gfn_start = op.op & ~DMOP_op_mask;
+        unsigned long gfn_end;
+
+        const_op = false;
 
         rc = -EINVAL;
         if ( data->pad )
@@ -396,8 +399,38 @@ static int dm_op(domid_t domid,
         if ( !hap_enabled(d) )
             break;
 
-        rc = hvm_map_mem_type_to_ioreq_server(d, data->id,
-                                              data->type, data->flags);
+        if ( gfn_start == 0 )
+            rc = hvm_map_mem_type_to_ioreq_server(d, data->id,
+                                                  data->type, data->flags);
+        /*
+         * Iterate p2m table when an ioreq server unmaps from p2m_ioreq_server,
+         * and reset the remaining p2m_ioreq_server entries back to p2m_ram_rw.
+         */
+        if ( (gfn_start > 0) || (data->flags == 0 && rc == 0) )
+        {
+            struct p2m_domain *p2m = p2m_get_hostp2m(d);
+
+            while ( read_atomic(&p2m->ioreq.entry_count) &&
+                    gfn_start <= p2m->max_mapped_pfn )
+            {
+                gfn_end = gfn_start + DMOP_op_mask;
+
+                p2m_finish_type_change(d, gfn_start, gfn_end,
+                                       p2m_ioreq_server, p2m_ram_rw);
+
+                gfn_start = gfn_end + 1;
+
+                /* Check for continuation if it's not the last iteration. */
+                if ( gfn_start <= p2m->max_mapped_pfn &&
+                     hypercall_preempt_check() )
+                {
+                    rc = -ERESTART;
+                    op.op |= gfn_start;
+                    break;
+                }
+            }
+        }
+
         break;
     }
 
diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c
index 94d7141..9a81f00 100644
--- a/xen/arch/x86/mm/p2m.c
+++ b/xen/arch/x86/mm/p2m.c
@@ -1038,6 +1038,35 @@ void p2m_change_type_range(struct domain *d,
     p2m_unlock(p2m);
 }
 
+/* Synchronously modify the p2m type of a range of gfns from ot to nt. */
+void p2m_finish_type_change(struct domain *d,
+                            unsigned long start, unsigned long end,
+                            p2m_type_t ot, p2m_type_t nt)
+{
+    struct p2m_domain *p2m = p2m_get_hostp2m(d);
+    p2m_type_t t;
+    unsigned long gfn = start;
+
+    ASSERT(start <= end);
+    ASSERT(ot != nt);
+    ASSERT(p2m_is_changeable(ot) && p2m_is_changeable(nt));
+
+    p2m_lock(p2m);
+
+    end = min(end, p2m->max_mapped_pfn);
+    while ( gfn <= end )
+    {
+        get_gfn_query_unlocked(d, gfn, &t);
+
+        if ( t == ot )
+            p2m_change_type_one(d, gfn, t, nt);
+
+        gfn++;
+    }
+
+    p2m_unlock(p2m);
+}
+
 /*
  * Returns:
  *    0              for success
diff --git a/xen/include/asm-x86/p2m.h b/xen/include/asm-x86/p2m.h
index 395f125..3eadd89 100644
--- a/xen/include/asm-x86/p2m.h
+++ b/xen/include/asm-x86/p2m.h
@@ -611,6 +611,11 @@ void p2m_change_type_range(struct domain *d,
 int p2m_change_type_one(struct domain *d, unsigned long gfn,
                         p2m_type_t ot, p2m_type_t nt);
 
+/* Synchronously change types across a range of p2m entries (start ... end) */
+void p2m_finish_type_change(struct domain *d,
+                            unsigned long start, unsigned long end,
+                            p2m_type_t ot, p2m_type_t nt);
+
 /* Report a change affecting memory types. */
 void p2m_memory_type_changed(struct domain *d);
 
diff --git a/xen/include/public/hvm/dm_op.h b/xen/include/public/hvm/dm_op.h
index c643b67..23b364b 100644
--- a/xen/include/public/hvm/dm_op.h
+++ b/xen/include/public/hvm/dm_op.h
@@ -343,8 +343,7 @@ struct xen_dm_op_map_mem_type_to_ioreq_server {
 };
 
 struct xen_dm_op {
-    uint32_t op;
-    uint32_t pad;
+    uint64_t op;
     union {
         struct xen_dm_op_create_ioreq_server create_ioreq_server;
         struct xen_dm_op_get_ioreq_server_info get_ioreq_server_info;
