diff --git a/net/smc/smc_loopback.c b/net/smc/smc_loopback.c
index a89dbf84aea5..2e734f8e08f5 100644
--- a/net/smc/smc_loopback.c
+++ b/net/smc/smc_loopback.c
@@ -13,6 +13,7 @@
 
 #include <linux/device.h>
 #include <linux/types.h>
+#include <linux/vmalloc.h>
 #include <net/smc.h>
 
 #include "smc_cdc.h"
@@ -24,6 +25,7 @@
 #define SMC_DMA_ADDR_INVALID	(~(dma_addr_t)0)
 
 static const char smc_lo_dev_name[] = "loopback-ism";
+static unsigned int smc_lo_dmb_type = SMC_LO_DMB_PHYS;
 static struct smc_lo_dev *lo_dev;
 static struct class *smc_class;
 
@@ -124,8 +126,50 @@ static ssize_t active_store(struct device *dev,
 	return count;
 }
 static DEVICE_ATTR_RW(active);
+
+static ssize_t dmb_type_show(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	struct smc_lo_dev *ldev =
+		container_of(dev, struct smc_lo_dev, dev);
+	const char *type;
+
+	switch (ldev->dmb_type) {
+	case SMC_LO_DMB_PHYS:
+		type = "Physically contiguous buffer";
+		break;
+	case SMC_LO_DMB_VIRT:
+		type = "Virtually contiguous buffer";
+		break;
+	default:
+		type = "Unknown type";
+	}
+
+	return sysfs_emit(buf, "%d: %s\n", ldev->dmb_type, type);
+}
+
+static ssize_t dmb_type_store(struct device *dev,
+			      struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	unsigned int dmb_type;
+	int ret;
+
+	ret = kstrtouint(buf, 0, &dmb_type);
+	if (ret)
+		return ret;
+
+	if (dmb_type != SMC_LO_DMB_PHYS &&
+	    dmb_type != SMC_LO_DMB_VIRT)
+		return -EINVAL;
+
+	smc_lo_dmb_type = dmb_type; /* re-activate to take effect */
+	return count;
+}
+static DEVICE_ATTR_RW(dmb_type);
 static struct attribute *smc_lo_attrs[] = {
 	&dev_attr_active.attr,
+	&dev_attr_dmb_type.attr,
 	&dev_attr_xfer_bytes.attr,
 	&dev_attr_dmbs_cnt.attr,
 	NULL,
@@ -170,8 +214,7 @@ static int smc_lo_register_dmb(struct smcd_dev *smcd, struct smcd_dmb *dmb,
 {
 	struct smc_lo_dmb_node *dmb_node, *tmp_node;
 	struct smc_lo_dev *ldev = smcd->priv;
-	int sba_idx, order, rc;
-	struct page *pages;
+	int sba_idx, rc;
 
 	/* check space for new dmb */
 	for_each_clear_bit(sba_idx, ldev->sba_idx_mask, SMC_LO_MAX_DMBS) {
@@ -188,16 +231,27 @@ static int smc_lo_register_dmb(struct smcd_dev *smcd, struct smcd_dmb *dmb,
 	}
 
 	dmb_node->sba_idx = sba_idx;
-	order = get_order(dmb->dmb_len);
-	pages = alloc_pages(GFP_KERNEL | __GFP_NOWARN |
-			    __GFP_NOMEMALLOC | __GFP_COMP |
-			    __GFP_NORETRY | __GFP_ZERO,
-			    order);
-	if (!pages) {
-		rc = -ENOMEM;
-		goto err_node;
+	if (ldev->dmb_type == SMC_LO_DMB_PHYS) {
+		struct page *pages;
+		int order;
+
+		order = get_order(dmb->dmb_len);
+		pages = alloc_pages(GFP_KERNEL | __GFP_NOWARN |
+				    __GFP_NOMEMALLOC | __GFP_COMP |
+				    __GFP_NORETRY | __GFP_ZERO,
+				    order);
+		if (!pages) {
+			rc = -ENOMEM;
+			goto err_node;
+		}
+		dmb_node->cpu_addr = (void *)page_address(pages);
+	} else {
+		dmb_node->cpu_addr = vzalloc(dmb->dmb_len);
+		if (!dmb_node->cpu_addr) {
+			rc = -ENOMEM;
+			goto err_node;
+		}
 	}
-	dmb_node->cpu_addr = (void *)page_address(pages);
 	dmb_node->len = dmb->dmb_len;
 	dmb_node->dma_addr = SMC_DMA_ADDR_INVALID;
 
@@ -251,7 +305,7 @@ static int smc_lo_unregister_dmb(struct smcd_dev *smcd, struct smcd_dmb *dmb)
 	write_unlock(&ldev->dmb_ht_lock);
 
 	clear_bit(dmb_node->sba_idx, ldev->sba_idx_mask);
-	kfree(dmb_node->cpu_addr);
+	kvfree(dmb_node->cpu_addr);
 	kfree(dmb_node);
 	SMC_LO_STAT_DMBS_DEC(ldev);
 
@@ -396,6 +450,7 @@ static int smcd_lo_register_dev(struct smc_lo_dev *ldev)
 	ldev->smcd = smcd;
 	smcd->priv = ldev;
 	smc_ism_set_v2_capable();
+	ldev->dmb_type = smc_lo_dmb_type;
 	mutex_lock(&smcd_dev_list.mutex);
 	list_add(&smcd->list, &smcd_dev_list.list);
 	mutex_unlock(&smcd_dev_list.mutex);
@@ -419,6 +474,7 @@ static void smcd_lo_unregister_dev(struct smc_lo_dev *ldev)
 	mutex_unlock(&smcd_dev_list.mutex);
 	kfree(smcd->conn);
 	kfree(smcd);
+	ldev->dmb_type = smc_lo_dmb_type;
 	smc_lo_clear_stats(ldev);
 }
 
diff --git a/net/smc/smc_loopback.h b/net/smc/smc_loopback.h
index d4572ca42f08..8ee5c6805fc4 100644
--- a/net/smc/smc_loopback.h
+++ b/net/smc/smc_loopback.h
@@ -23,6 +23,11 @@
 #define SMC_LO_DMBS_HASH_BITS	12
 #define SMC_LO_CHID		0xFFFF
 
+enum {
+	SMC_LO_DMB_PHYS,
+	SMC_LO_DMB_VIRT,
+};
+
 struct smc_lo_dmb_node {
 	struct hlist_node list;
 	u64 token;
@@ -41,6 +46,7 @@ struct smc_lo_dev {
 	struct smcd_dev *smcd;
 	struct device dev;
 	u8 active;
+	u8 dmb_type;
 	u16 chid;
 	struct smcd_gid local_gid;
 	struct smc_lo_dev_stats64 __percpu *stats;
