diff -urpN a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
--- a/arch/x86/kernel/setup.c	2016-11-20 01:17:41.000000000 +0000
+++ b/arch/x86/kernel/setup.c	2017-01-04 23:10:26.473086206 +0000
@@ -49,6 +49,7 @@
 #include <asm/pci-direct.h>
 #include <linux/init_ohci1394_dma.h>
 #include <linux/kvm_para.h>
+#include <linux/early_dma_alloc.h>
 #include <linux/dma-contiguous.h>
 
 #include <linux/errno.h>
@@ -1243,6 +1244,10 @@ void __init setup_arch(char **cmdline_p)
 
 	arch_init_ideal_nops();
 
+#ifdef CONFIG_EARLY_DMA_ALLOC
+	eda_init();
+#endif
+	
 	register_refined_jiffies(CLOCK_TICK_RATE);
 
 #ifdef CONFIG_EFI
diff -urpN a/drivers/misc/Kconfig b/drivers/misc/Kconfig
--- a/drivers/misc/Kconfig	2016-11-20 01:17:41.000000000 +0000
+++ b/drivers/misc/Kconfig	2017-01-04 23:11:14.305087244 +0000
@@ -496,6 +496,34 @@ config USB_SWITCH_FSA9480
 	  stereo and mono audio, video, microphone and UART data to use
 	  a common connector port.
 
+config EARLY_DMA_ALLOC
+	bool "Early DMA Memory Allocator"
+	depends on HAS_DMA
+
+	---help---
+	  This driver locks down a region of DMA accessible memory
+          early in the boot process.  This memory can be used by other
+          drivers that might rmmod/insmod, insuring the memory region
+          does not become fragmented.
+
+config EDA_DEF_SIZE
+	hex "EDA Default Region Size"
+	depends on EARLY_DMA_ALLOC
+	default 0x04000000
+	help
+	  Default size of the reserved memory pool, if not altered by the
+	  open firmware interface or kernel boot parameter. This memory
+	  will not be accessable to the rest of the system. Default is
+	  64MB.
+
+config EDA_DEF_ALIGN
+	hex "EDA Default Alignment"
+	depends on EARLY_DMA_ALLOC
+	default 0x00100000
+	help
+	  Default alignment of the memory region. Default is 1MB.
+
+
 config LATTICE_ECP3_CONFIG
 	tristate "Lattice ECP3 FPGA bitstream configuration via SPI"
 	depends on SPI && SYSFS
diff -urpN a/drivers/misc/Makefile b/drivers/misc/Makefile
--- a/drivers/misc/Makefile	2016-11-20 01:17:41.000000000 +0000
+++ b/drivers/misc/Makefile	2017-01-04 23:12:15.781088578 +0000
@@ -56,3 +56,4 @@ obj-y				+= mic/
 obj-$(CONFIG_GENWQE)		+= genwqe/
 obj-$(CONFIG_ECHO)		+= echo/
 obj-$(CONFIG_VEXPRESS_SYSCFG)	+= vexpress-syscfg.o
+obj-$(CONFIG_EARLY_DMA_ALLOC)	+= early_dma_alloc.o
diff -urpN a/drivers/misc/early_dma_alloc.c b/drivers/misc/early_dma_alloc.c
--- a/drivers/misc/early_dma_alloc.c	1970-01-01 00:00:00.000000000 +0000
+++ b/drivers/misc/early_dma_alloc.c	2017-01-04 23:13:09.209089737 +0000
@@ -0,0 +1,223 @@
+/*
+ * Early DMA Memory Allocator
+ *
+ * Copyright © 2013,2014 Cumulus Networks, Inc.
+ *
+ * Author: Curt Brune <curt@cumulusnetworks.com>
+ * Modified: Jonathan Toppins <jtoppins@cumulusnetworks.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+/*
+ * This driver allocates a region of DMA accessible memory, making it
+ * available to one other device driver.
+ *
+ * The client device driver may be unloaded and reloaded over time.
+ * This driver keeps the DMA region from becoming fragmented across
+ * module reloads.
+ *
+ * Memory Region Restrictions
+ * --------------------------
+ * The memory region allocated by EDA MUST exist below a 4GB limit. This
+ * is because EDA's primary (only at time of writing) user is the
+ * Broadcom BDE driver wich assumes a 32-bit physical address space and
+ * assumes paddr is no more than 32-bits wide. Furthermore, before porting
+ * the BDE driver to use EDA the BDE driver specifically checked if the
+ * memory region provided by highmem was less than 4GB. We assume Broadcom
+ * knew what they were doing and there is a specific reason why this 4GB
+ * limit is needed, so we enforce this limit by checking the physical address
+ * after allocation.
+ *
+ * Memory Region Size and Alignment
+ * --------------------------------
+ * This driver allows three ways for the user to define the DMA memory
+ * that will be created, listed in order of preference.
+ * 1. The user may specify on the kernel command line in the boot loader
+ *    the "eda_mem" option, this option has the format "size@alignment",
+ *    example: eda_mem=0x04000000@0x00100000
+ * 2. This driver looks for a device tree node compatible with
+ *    "early-dma-alloc".  The "region_size" property of the node contains
+ *    the size, in bytes, of the desired DMA memory region.  The
+ *    "alignment" property contains the desired memory alignment of the
+ *    region.
+ * 3. Finally if neither of the above are provided the Kbuild changable,
+ *    compiled in default size and alignment will be used.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/of_platform.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/dma-mapping.h>
+#include <linux/bootmem.h>
+#include <linux/early_dma_alloc.h>
+
+#if (!defined CONFIG_EDA_DEF_SIZE) || \
+	(!defined CONFIG_EDA_DEF_ALIGN)
+#error incorrect kernel config - fix it
+#endif
+
+// #define DEBUG
+#if (defined DEBUG)
+#define eda_debug(fmt, ... ) \
+	printk(KERN_ERR "eda-debug:%s(): " fmt "\n", __func__ , \
+	##__VA_ARGS__)
+#else
+#define eda_debug(fmt, ... )
+#endif
+
+#define eda_info(fmt, ... ) \
+	printk(KERN_INFO "eda: " fmt "\n", ##__VA_ARGS__)
+
+static uint32_t dma_size;
+static void     *dma_vaddr;
+static u32      dma_align __initdata;
+static bool     eda_cmdline  __initdata;
+
+static int __init setup_eda_mem(char *str)
+{
+	char *endp;
+
+	dma_size = memparse(str, &endp) & PAGE_MASK;
+	if (*endp == '@')
+		dma_align = memparse(endp + 1, NULL) & PAGE_MASK;
+	eda_cmdline = true;
+	return 0;
+}
+early_param("eda_mem", setup_eda_mem);
+
+static int __init of_eda_init(uint32_t *size, u32 *align)
+#ifdef CONFIG_OF_FLATTREE
+{
+	int                 rc           = -ENODEV;
+	struct device_node  *np          = NULL;
+	const u32           *region_sz_p = NULL;
+	const u32           *align_p     = NULL;
+	u32                 prop_sz      = 0;
+
+	eda_debug("entry");
+
+	/* is a programming error make it really painful so it gets fixed */
+	BUG_ON(NULL == size || NULL == align);
+
+	np = of_find_compatible_node(NULL, NULL, "early-dma-alloc");
+	if (!np) {
+		printk(KERN_WARNING "WARN: Can not find `early-dma-alloc'"
+		       " device tree node.\n");
+		goto cleanup;
+	}
+
+	region_sz_p = of_get_property(np, "region_size", &prop_sz);
+	if (!region_sz_p || (prop_sz != sizeof(*region_sz_p))) {
+		printk(KERN_ERR "ERROR: Can not find `region_size' property"
+		       " in early-dma-alloc device tree node.\n");
+		goto cleanup;
+	}
+	*size = *region_sz_p;
+
+	align_p = of_get_property(np, "alignment", &prop_sz);
+	if (!align_p || (prop_sz != sizeof(*align_p))) {
+		printk(KERN_ERR "ERROR: Can not find `alignment' property in"
+		       "early-dma-alloc device tree node.\n");
+		goto cleanup;
+	}
+	*align = *align_p;
+	rc = 0;
+
+	eda_debug("cleanup");
+
+cleanup:
+	of_node_put(np);
+	return rc;
+
+}
+#else
+{
+	return -ENODEV;
+}
+#endif
+
+int eda_dma_info_get(void **vaddr, uint32_t *paddr, uint32_t *size)
+{
+	eda_debug("entry");
+
+	if (!dma_vaddr)
+		return -ENOMEM;
+
+	if (!vaddr || !paddr || !size)
+		return -EINVAL;
+
+	*vaddr = dma_vaddr;
+	*paddr = (uint32_t) virt_to_phys(dma_vaddr);
+	*size  = dma_size;
+
+	eda_debug("returning -- dma_vaddr: 0x%pK, dma_paddr: 0x%08x,"
+	          " size: 0x%08x", *vaddr, *paddr, *size);
+
+	return 0;
+}
+EXPORT_SYMBOL(eda_dma_info_get);
+
+int __init eda_init(void)
+{
+	int rc    = 0;
+
+	if (eda_cmdline) {
+		if (!dma_align)
+			dma_align = CONFIG_EDA_DEF_ALIGN;
+		if (!dma_size)
+			dma_size  = CONFIG_EDA_DEF_SIZE;
+		eda_debug("size & alignment came from: kernel cmdline");
+	} else if (!of_eda_init(&dma_size, &dma_align)) {
+		eda_debug("size & alignment came from: open firmware entry");
+	} else {
+		dma_align = CONFIG_EDA_DEF_ALIGN;
+		dma_size  = CONFIG_EDA_DEF_SIZE;
+		eda_debug("size & alignment came from: compiled in defaults");
+	}
+
+	dma_vaddr = __alloc_bootmem_low(dma_size, dma_align, 0);
+	/*
+	 * enforce EDA's requirement to allocate the memory region below a
+	 * 32-bit limit.
+	 */
+	if (virt_to_phys(dma_vaddr) > 0xFFFFFFFFULL) {
+		rc = -ENOMEM;
+		printk(KERN_ERR "ERROR: DMA memory beyond 32-bit address"
+		       " space not supported.\n");
+		goto cleanup;
+	}
+
+	eda_info("dma_vaddr: 0x%pK, dma_paddr: 0x%016llx, size: 0x%08x,"
+	         " alignment: 0x%08x",
+		 dma_vaddr, (unsigned long long) virt_to_phys(dma_vaddr),
+		 dma_size, dma_align);
+cleanup:
+	if (rc && dma_vaddr) {
+		free_bootmem(dma_vaddr, dma_size);
+	}
+	if (rc) {
+		dma_vaddr = NULL;
+		dma_size  = 0;
+	}
+	return rc;
+}
+EXPORT_SYMBOL(eda_init);
diff -urpN a/include/linux/early_dma_alloc.h b/include/linux/early_dma_alloc.h
--- a/include/linux/early_dma_alloc.h	1970-01-01 00:00:00.000000000 +0000
+++ b/include/linux/early_dma_alloc.h	2017-01-04 23:13:59.405090826 +0000
@@ -0,0 +1,36 @@
+/*
+ * Early DMA Memory Allocator
+ *
+ * Copyright © 2013 Cumulus Networks, Inc.
+ *
+ * Author: Curt Brune <curt@cumulusnetworks.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef EARLY_DMA_ALLOC_H__
+#define EARLY_DMA_ALLOC_H__
+
+#ifdef __KERNEL__
+
+#include <linux/types.h>
+
+extern int eda_init(void);
+extern int eda_dma_info_get(void** vaddr, uint32_t* paddr, uint32_t* size);
+
+#endif /* __KERNEL__ */
+
+#endif /* EARLY_DMA_ALLOC_H__ */
