[v3] axon_ram: add dax_operations support
diff mbox

Message ID 149264111867.36586.15762148888692084363.stgit@dwillia2-desk3.amr.corp.intel.com
State New
Headers show

Commit Message

Dan Williams April 19, 2017, 10:32 p.m. UTC
Setup a dax_device to have the same lifetime as the axon_ram block
device and add a ->direct_access() method that is equivalent to
axon_ram_direct_access(). Once fs/dax.c has been converted to use
dax_operations the old axon_ram_direct_access() will be removed.

Reported-by: Gerald Schaefer <gerald.schaefer@de.ibm.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
Changes since v2:
* fix return code in the alloc_dax() failure case (Gerald)

 arch/powerpc/platforms/Kconfig |    1 +
 arch/powerpc/sysdev/axonram.c  |   48 +++++++++++++++++++++++++++++++++++-----
 2 files changed, 43 insertions(+), 6 deletions(-)

Comments

kernel test robot April 20, 2017, 3:01 a.m. UTC | #1
Hi Dan,

[auto build test ERROR on powerpc/next]
[also build test ERROR on v4.11-rc7 next-20170419]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Dan-Williams/axon_ram-add-dax_operations-support/20170420-091615
base:   https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git next
config: powerpc-defconfig (attached as .config)
compiler: powerpc64-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
        wget https://raw.githubusercontent.com/01org/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=powerpc 

All errors (new ones prefixed by >>):

   arch/powerpc/sysdev/axonram.c: In function 'axon_ram_dax_direct_access':
>> arch/powerpc/sysdev/axonram.c:176:31: error: implicit declaration of function 'dax_get_private' [-Werror=implicit-function-declaration]
     struct axon_ram_bank *bank = dax_get_private(dax_dev);
                                  ^~~~~~~~~~~~~~~
>> arch/powerpc/sysdev/axonram.c:176:31: error: initialization makes pointer from integer without a cast [-Werror=int-conversion]
   arch/powerpc/sysdev/axonram.c: At top level:
>> arch/powerpc/sysdev/axonram.c:181:21: error: variable 'axon_ram_dax_ops' has initializer but incomplete type
    static const struct dax_operations axon_ram_dax_ops = {
                        ^~~~~~~~~~~~~~
>> arch/powerpc/sysdev/axonram.c:182:2: error: unknown field 'direct_access' specified in initializer
     .direct_access = axon_ram_dax_direct_access,
     ^
   arch/powerpc/sysdev/axonram.c:182:19: error: excess elements in struct initializer [-Werror]
     .direct_access = axon_ram_dax_direct_access,
                      ^~~~~~~~~~~~~~~~~~~~~~~~~~
   arch/powerpc/sysdev/axonram.c:182:19: note: (near initialization for 'axon_ram_dax_ops')
   arch/powerpc/sysdev/axonram.c: In function 'axon_ram_probe':
>> arch/powerpc/sysdev/axonram.c:255:18: error: implicit declaration of function 'alloc_dax' [-Werror=implicit-function-declaration]
     bank->dax_dev = alloc_dax(bank, bank->disk->disk_name,
                     ^~~~~~~~~
>> arch/powerpc/sysdev/axonram.c:255:16: error: assignment makes pointer from integer without a cast [-Werror=int-conversion]
     bank->dax_dev = alloc_dax(bank, bank->disk->disk_name,
                   ^
>> arch/powerpc/sysdev/axonram.c:313:3: error: implicit declaration of function 'kill_dax' [-Werror=implicit-function-declaration]
      kill_dax(bank->dax_dev);
      ^~~~~~~~
>> arch/powerpc/sysdev/axonram.c:314:3: error: implicit declaration of function 'put_dax' [-Werror=implicit-function-declaration]
      put_dax(bank->dax_dev);
      ^~~~~~~
   arch/powerpc/sysdev/axonram.c: At top level:
>> arch/powerpc/sysdev/axonram.c:181:36: error: storage size of 'axon_ram_dax_ops' isn't known
    static const struct dax_operations axon_ram_dax_ops = {
                                       ^~~~~~~~~~~~~~~~
   cc1: all warnings being treated as errors

vim +/dax_get_private +176 arch/powerpc/sysdev/axonram.c

   170	};
   171	
   172	static long
   173	axon_ram_dax_direct_access(struct dax_device *dax_dev, pgoff_t pgoff, long nr_pages,
   174			       void **kaddr, pfn_t *pfn)
   175	{
 > 176		struct axon_ram_bank *bank = dax_get_private(dax_dev);
   177	
   178		return __axon_ram_direct_access(bank, pgoff, nr_pages, kaddr, pfn);
   179	}
   180	
 > 181	static const struct dax_operations axon_ram_dax_ops = {
 > 182		.direct_access = axon_ram_dax_direct_access,
   183	};
   184	
   185	/**
   186	 * axon_ram_probe - probe() method for platform driver
   187	 * @device: see platform_driver method
   188	 */
   189	static int axon_ram_probe(struct platform_device *device)
   190	{
   191		static int axon_ram_bank_id = -1;
   192		struct axon_ram_bank *bank;
   193		struct resource resource;
   194		int rc = 0;
   195	
   196		axon_ram_bank_id++;
   197	
   198		dev_info(&device->dev, "Found memory controller on %s\n",
   199				device->dev.of_node->full_name);
   200	
   201		bank = kzalloc(sizeof(struct axon_ram_bank), GFP_KERNEL);
   202		if (bank == NULL) {
   203			dev_err(&device->dev, "Out of memory\n");
   204			rc = -ENOMEM;
   205			goto failed;
   206		}
   207	
   208		device->dev.platform_data = bank;
   209	
   210		bank->device = device;
   211	
   212		if (of_address_to_resource(device->dev.of_node, 0, &resource) != 0) {
   213			dev_err(&device->dev, "Cannot access device tree\n");
   214			rc = -EFAULT;
   215			goto failed;
   216		}
   217	
   218		bank->size = resource_size(&resource);
   219	
   220		if (bank->size == 0) {
   221			dev_err(&device->dev, "No DDR2 memory found for %s%d\n",
   222					AXON_RAM_DEVICE_NAME, axon_ram_bank_id);
   223			rc = -ENODEV;
   224			goto failed;
   225		}
   226	
   227		dev_info(&device->dev, "Register DDR2 memory device %s%d with %luMB\n",
   228				AXON_RAM_DEVICE_NAME, axon_ram_bank_id, bank->size >> 20);
   229	
   230		bank->ph_addr = resource.start;
   231		bank->io_addr = (unsigned long) ioremap_prot(
   232				bank->ph_addr, bank->size, _PAGE_NO_CACHE);
   233		if (bank->io_addr == 0) {
   234			dev_err(&device->dev, "ioremap() failed\n");
   235			rc = -EFAULT;
   236			goto failed;
   237		}
   238	
   239		bank->disk = alloc_disk(AXON_RAM_MINORS_PER_DISK);
   240		if (bank->disk == NULL) {
   241			dev_err(&device->dev, "Cannot register disk\n");
   242			rc = -EFAULT;
   243			goto failed;
   244		}
   245	
   246	
   247		bank->disk->major = azfs_major;
   248		bank->disk->first_minor = azfs_minor;
   249		bank->disk->fops = &axon_ram_devops;
   250		bank->disk->private_data = bank;
   251	
   252		sprintf(bank->disk->disk_name, "%s%d",
   253				AXON_RAM_DEVICE_NAME, axon_ram_bank_id);
   254	
 > 255		bank->dax_dev = alloc_dax(bank, bank->disk->disk_name,
   256				&axon_ram_dax_ops);
   257		if (!bank->dax_dev) {
   258			rc = -ENOMEM;
   259			goto failed;
   260		}
   261	
   262		bank->disk->queue = blk_alloc_queue(GFP_KERNEL);
   263		if (bank->disk->queue == NULL) {
   264			dev_err(&device->dev, "Cannot register disk queue\n");
   265			rc = -EFAULT;
   266			goto failed;
   267		}
   268	
   269		set_capacity(bank->disk, bank->size >> AXON_RAM_SECTOR_SHIFT);
   270		blk_queue_make_request(bank->disk->queue, axon_ram_make_request);
   271		blk_queue_logical_block_size(bank->disk->queue, AXON_RAM_SECTOR_SIZE);
   272		device_add_disk(&device->dev, bank->disk);
   273	
   274		bank->irq_id = irq_of_parse_and_map(device->dev.of_node, 0);
   275		if (!bank->irq_id) {
   276			dev_err(&device->dev, "Cannot access ECC interrupt ID\n");
   277			rc = -EFAULT;
   278			goto failed;
   279		}
   280	
   281		rc = request_irq(bank->irq_id, axon_ram_irq_handler,
   282				AXON_RAM_IRQ_FLAGS, bank->disk->disk_name, device);
   283		if (rc != 0) {
   284			dev_err(&device->dev, "Cannot register ECC interrupt handler\n");
   285			bank->irq_id = 0;
   286			rc = -EFAULT;
   287			goto failed;
   288		}
   289	
   290		rc = device_create_file(&device->dev, &dev_attr_ecc);
   291		if (rc != 0) {
   292			dev_err(&device->dev, "Cannot create sysfs file\n");
   293			rc = -EFAULT;
   294			goto failed;
   295		}
   296	
   297		azfs_minor += bank->disk->minors;
   298	
   299		return 0;
   300	
   301	failed:
   302		if (bank != NULL) {
   303			if (bank->irq_id)
   304				free_irq(bank->irq_id, device);
   305			if (bank->disk != NULL) {
   306				if (bank->disk->major > 0)
   307					unregister_blkdev(bank->disk->major,
   308							bank->disk->disk_name);
   309				if (bank->disk->flags & GENHD_FL_UP)
   310					del_gendisk(bank->disk);
   311				put_disk(bank->disk);
   312			}
 > 313			kill_dax(bank->dax_dev);
 > 314			put_dax(bank->dax_dev);
   315			device->dev.platform_data = NULL;
   316			if (bank->io_addr != 0)
   317				iounmap((void __iomem *) bank->io_addr);

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
Dan Williams April 20, 2017, 3:16 a.m. UTC | #2
On Wed, Apr 19, 2017 at 8:01 PM, kbuild test robot <lkp@intel.com> wrote:
> Hi Dan,
>
> [auto build test ERROR on powerpc/next]
> [also build test ERROR on v4.11-rc7 next-20170419]
> [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
>
>
> url:    https://github.com/0day-ci/linux/commits/Dan-Williams/axon_ram-add-dax_operations-support/20170420-091615
> base:   https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git next

Hi kbuild team, yes this is the wrong base. It's part of a larger
series [1] and I'm just re-sending a few select patches with updates
from review, rather than the full 33 patch series. Any better way to
send individual updates to a patch in a series without re-sending the
whole series?

[1]: https://lkml.org/lkml/2017/4/14/495
kernel test robot April 20, 2017, 5:46 a.m. UTC | #3
Hi Dan,

[auto build test WARNING on powerpc/next]
[also build test WARNING on v4.11-rc7 next-20170419]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Dan-Williams/axon_ram-add-dax_operations-support/20170420-091615
base:   https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git next
config: powerpc-allyesconfig (attached as .config)
compiler: powerpc64-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
        wget https://raw.githubusercontent.com/01org/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=powerpc 

All warnings (new ones prefixed by >>):

   arch/powerpc/sysdev/axonram.c: In function 'axon_ram_dax_direct_access':
   arch/powerpc/sysdev/axonram.c:176:31: error: implicit declaration of function 'dax_get_private' [-Werror=implicit-function-declaration]
     struct axon_ram_bank *bank = dax_get_private(dax_dev);
                                  ^~~~~~~~~~~~~~~
>> arch/powerpc/sysdev/axonram.c:176:31: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
   arch/powerpc/sysdev/axonram.c: At top level:
   arch/powerpc/sysdev/axonram.c:181:21: error: variable 'axon_ram_dax_ops' has initializer but incomplete type
    static const struct dax_operations axon_ram_dax_ops = {
                        ^~~~~~~~~~~~~~
   arch/powerpc/sysdev/axonram.c:182:2: error: unknown field 'direct_access' specified in initializer
     .direct_access = axon_ram_dax_direct_access,
     ^
>> arch/powerpc/sysdev/axonram.c:182:19: warning: excess elements in struct initializer
     .direct_access = axon_ram_dax_direct_access,
                      ^~~~~~~~~~~~~~~~~~~~~~~~~~
   arch/powerpc/sysdev/axonram.c:182:19: note: (near initialization for 'axon_ram_dax_ops')
   arch/powerpc/sysdev/axonram.c: In function 'axon_ram_probe':
   arch/powerpc/sysdev/axonram.c:255:18: error: implicit declaration of function 'alloc_dax' [-Werror=implicit-function-declaration]
     bank->dax_dev = alloc_dax(bank, bank->disk->disk_name,
                     ^~~~~~~~~
>> arch/powerpc/sysdev/axonram.c:255:16: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
     bank->dax_dev = alloc_dax(bank, bank->disk->disk_name,
                   ^
   arch/powerpc/sysdev/axonram.c:313:3: error: implicit declaration of function 'kill_dax' [-Werror=implicit-function-declaration]
      kill_dax(bank->dax_dev);
      ^~~~~~~~
   arch/powerpc/sysdev/axonram.c:314:3: error: implicit declaration of function 'put_dax' [-Werror=implicit-function-declaration]
      put_dax(bank->dax_dev);
      ^~~~~~~
   arch/powerpc/sysdev/axonram.c: At top level:
   arch/powerpc/sysdev/axonram.c:181:36: error: storage size of 'axon_ram_dax_ops' isn't known
    static const struct dax_operations axon_ram_dax_ops = {
                                       ^~~~~~~~~~~~~~~~
   cc1: some warnings being treated as errors

vim +176 arch/powerpc/sysdev/axonram.c

   170	};
   171	
   172	static long
   173	axon_ram_dax_direct_access(struct dax_device *dax_dev, pgoff_t pgoff, long nr_pages,
   174			       void **kaddr, pfn_t *pfn)
   175	{
 > 176		struct axon_ram_bank *bank = dax_get_private(dax_dev);
   177	
   178		return __axon_ram_direct_access(bank, pgoff, nr_pages, kaddr, pfn);
   179	}
   180	
   181	static const struct dax_operations axon_ram_dax_ops = {
 > 182		.direct_access = axon_ram_dax_direct_access,
   183	};
   184	
   185	/**
   186	 * axon_ram_probe - probe() method for platform driver
   187	 * @device: see platform_driver method
   188	 */
   189	static int axon_ram_probe(struct platform_device *device)
   190	{
   191		static int axon_ram_bank_id = -1;
   192		struct axon_ram_bank *bank;
   193		struct resource resource;
   194		int rc = 0;
   195	
   196		axon_ram_bank_id++;
   197	
   198		dev_info(&device->dev, "Found memory controller on %s\n",
   199				device->dev.of_node->full_name);
   200	
   201		bank = kzalloc(sizeof(struct axon_ram_bank), GFP_KERNEL);
   202		if (bank == NULL) {
   203			dev_err(&device->dev, "Out of memory\n");
   204			rc = -ENOMEM;
   205			goto failed;
   206		}
   207	
   208		device->dev.platform_data = bank;
   209	
   210		bank->device = device;
   211	
   212		if (of_address_to_resource(device->dev.of_node, 0, &resource) != 0) {
   213			dev_err(&device->dev, "Cannot access device tree\n");
   214			rc = -EFAULT;
   215			goto failed;
   216		}
   217	
   218		bank->size = resource_size(&resource);
   219	
   220		if (bank->size == 0) {
   221			dev_err(&device->dev, "No DDR2 memory found for %s%d\n",
   222					AXON_RAM_DEVICE_NAME, axon_ram_bank_id);
   223			rc = -ENODEV;
   224			goto failed;
   225		}
   226	
   227		dev_info(&device->dev, "Register DDR2 memory device %s%d with %luMB\n",
   228				AXON_RAM_DEVICE_NAME, axon_ram_bank_id, bank->size >> 20);
   229	
   230		bank->ph_addr = resource.start;
   231		bank->io_addr = (unsigned long) ioremap_prot(
   232				bank->ph_addr, bank->size, _PAGE_NO_CACHE);
   233		if (bank->io_addr == 0) {
   234			dev_err(&device->dev, "ioremap() failed\n");
   235			rc = -EFAULT;
   236			goto failed;
   237		}
   238	
   239		bank->disk = alloc_disk(AXON_RAM_MINORS_PER_DISK);
   240		if (bank->disk == NULL) {
   241			dev_err(&device->dev, "Cannot register disk\n");
   242			rc = -EFAULT;
   243			goto failed;
   244		}
   245	
   246	
   247		bank->disk->major = azfs_major;
   248		bank->disk->first_minor = azfs_minor;
   249		bank->disk->fops = &axon_ram_devops;
   250		bank->disk->private_data = bank;
   251	
   252		sprintf(bank->disk->disk_name, "%s%d",
   253				AXON_RAM_DEVICE_NAME, axon_ram_bank_id);
   254	
 > 255		bank->dax_dev = alloc_dax(bank, bank->disk->disk_name,
   256				&axon_ram_dax_ops);
   257		if (!bank->dax_dev) {
   258			rc = -ENOMEM;

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
Ye Xiaolong April 26, 2017, 6:14 a.m. UTC | #4
On 04/19, Dan Williams wrote:
>On Wed, Apr 19, 2017 at 8:01 PM, kbuild test robot <lkp@intel.com> wrote:
>> Hi Dan,
>>
>> [auto build test ERROR on powerpc/next]
>> [also build test ERROR on v4.11-rc7 next-20170419]
>> [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
>>
>>
>> url:    https://github.com/0day-ci/linux/commits/Dan-Williams/axon_ram-add-dax_operations-support/20170420-091615
>> base:   https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git next
>
>Hi kbuild team, yes this is the wrong base. It's part of a larger
>series [1] and I'm just re-sending a few select patches with updates
>from review, rather than the full 33 patch series. Any better way to
>send individual updates to a patch in a series without re-sending the
>whole series?

Thanks for the feedback, as it's a common practice in community, we are
developing a new feature to recognize the updated patch of a patch series, and
apply it together with the whole patchset other than applying it individually.

Thanks,
Xiaolong

>
>[1]: https://lkml.org/lkml/2017/4/14/495
>_______________________________________________
>kbuild-all mailing list
>kbuild-all@lists.01.org
>https://lists.01.org/mailman/listinfo/kbuild-all

Patch
diff mbox

diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index 7e3a2ebba29b..33244e3d9375 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -284,6 +284,7 @@  config CPM2
 config AXON_RAM
 	tristate "Axon DDR2 memory device driver"
 	depends on PPC_IBM_CELL_BLADE && BLOCK
+	select DAX
 	default m
 	help
 	  It registers one block device per Axon's DDR2 memory bank found
diff --git a/arch/powerpc/sysdev/axonram.c b/arch/powerpc/sysdev/axonram.c
index f523ac883150..171ba86a3494 100644
--- a/arch/powerpc/sysdev/axonram.c
+++ b/arch/powerpc/sysdev/axonram.c
@@ -25,6 +25,7 @@ 
 
 #include <linux/bio.h>
 #include <linux/blkdev.h>
+#include <linux/dax.h>
 #include <linux/device.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
@@ -62,6 +63,7 @@  static int azfs_major, azfs_minor;
 struct axon_ram_bank {
 	struct platform_device	*device;
 	struct gendisk		*disk;
+	struct dax_device	*dax_dev;
 	unsigned int		irq_id;
 	unsigned long		ph_addr;
 	unsigned long		io_addr;
@@ -137,25 +139,47 @@  axon_ram_make_request(struct request_queue *queue, struct bio *bio)
 	return BLK_QC_T_NONE;
 }
 
+static long
+__axon_ram_direct_access(struct axon_ram_bank *bank, pgoff_t pgoff, long nr_pages,
+		       void **kaddr, pfn_t *pfn)
+{
+	resource_size_t offset = pgoff * PAGE_SIZE;
+
+	*kaddr = (void *) bank->io_addr + offset;
+	*pfn = phys_to_pfn_t(bank->ph_addr + offset, PFN_DEV);
+	return (bank->size - offset) / PAGE_SIZE;
+}
+
 /**
  * axon_ram_direct_access - direct_access() method for block device
  * @device, @sector, @data: see block_device_operations method
  */
 static long
-axon_ram_direct_access(struct block_device *device, sector_t sector,
+axon_ram_blk_direct_access(struct block_device *device, sector_t sector,
 		       void **kaddr, pfn_t *pfn, long size)
 {
 	struct axon_ram_bank *bank = device->bd_disk->private_data;
-	loff_t offset = (loff_t)sector << AXON_RAM_SECTOR_SHIFT;
 
-	*kaddr = (void *) bank->io_addr + offset;
-	*pfn = phys_to_pfn_t(bank->ph_addr + offset, PFN_DEV);
-	return bank->size - offset;
+	return __axon_ram_direct_access(bank, (sector * 512) / PAGE_SIZE,
+			size / PAGE_SIZE, kaddr, pfn) * PAGE_SIZE;
 }
 
 static const struct block_device_operations axon_ram_devops = {
 	.owner		= THIS_MODULE,
-	.direct_access	= axon_ram_direct_access
+	.direct_access	= axon_ram_blk_direct_access
+};
+
+static long
+axon_ram_dax_direct_access(struct dax_device *dax_dev, pgoff_t pgoff, long nr_pages,
+		       void **kaddr, pfn_t *pfn)
+{
+	struct axon_ram_bank *bank = dax_get_private(dax_dev);
+
+	return __axon_ram_direct_access(bank, pgoff, nr_pages, kaddr, pfn);
+}
+
+static const struct dax_operations axon_ram_dax_ops = {
+	.direct_access = axon_ram_dax_direct_access,
 };
 
 /**
@@ -219,6 +243,7 @@  static int axon_ram_probe(struct platform_device *device)
 		goto failed;
 	}
 
+
 	bank->disk->major = azfs_major;
 	bank->disk->first_minor = azfs_minor;
 	bank->disk->fops = &axon_ram_devops;
@@ -227,6 +252,13 @@  static int axon_ram_probe(struct platform_device *device)
 	sprintf(bank->disk->disk_name, "%s%d",
 			AXON_RAM_DEVICE_NAME, axon_ram_bank_id);
 
+	bank->dax_dev = alloc_dax(bank, bank->disk->disk_name,
+			&axon_ram_dax_ops);
+	if (!bank->dax_dev) {
+		rc = -ENOMEM;
+		goto failed;
+	}
+
 	bank->disk->queue = blk_alloc_queue(GFP_KERNEL);
 	if (bank->disk->queue == NULL) {
 		dev_err(&device->dev, "Cannot register disk queue\n");
@@ -278,6 +310,8 @@  static int axon_ram_probe(struct platform_device *device)
 				del_gendisk(bank->disk);
 			put_disk(bank->disk);
 		}
+		kill_dax(bank->dax_dev);
+		put_dax(bank->dax_dev);
 		device->dev.platform_data = NULL;
 		if (bank->io_addr != 0)
 			iounmap((void __iomem *) bank->io_addr);
@@ -300,6 +334,8 @@  axon_ram_remove(struct platform_device *device)
 
 	device_remove_file(&device->dev, &dev_attr_ecc);
 	free_irq(bank->irq_id, device);
+	kill_dax(bank->dax_dev);
+	put_dax(bank->dax_dev);
 	del_gendisk(bank->disk);
 	put_disk(bank->disk);
 	iounmap((void __iomem *) bank->io_addr);