static enum diag204_format diag204_info_type;  /* used diag 204 data format */
 
 static void *diag204_buf;              /* 4K aligned buffer for diag204 data */
-static void *diag204_buf_vmalloc;      /* vmalloc pointer for diag204 data */
 static int diag204_buf_pages;          /* number of pages for diag204 data */
 
 static struct dentry *dbfs_d204_file;
 
 static void diag204_free_buffer(void)
 {
-       if (!diag204_buf)
-               return;
-       if (diag204_buf_vmalloc) {
-               vfree(diag204_buf_vmalloc);
-               diag204_buf_vmalloc = NULL;
-       } else {
-               free_pages((unsigned long) diag204_buf, 0);
-       }
+       vfree(diag204_buf);
        diag204_buf = NULL;
 }
 
        return (void *) PAGE_ALIGN((unsigned long) ptr);
 }
 
-static void *diag204_alloc_vbuf(int pages)
-{
-       /* The buffer has to be page aligned! */
-       diag204_buf_vmalloc = vmalloc(array_size(PAGE_SIZE, (pages + 1)));
-       if (!diag204_buf_vmalloc)
-               return ERR_PTR(-ENOMEM);
-       diag204_buf = page_align_ptr(diag204_buf_vmalloc);
-       diag204_buf_pages = pages;
-       return diag204_buf;
-}
-
-static void *diag204_alloc_rbuf(void)
-{
-       diag204_buf = (void*)__get_free_pages(GFP_KERNEL,0);
-       if (!diag204_buf)
-               return ERR_PTR(-ENOMEM);
-       diag204_buf_pages = 1;
-       return diag204_buf;
-}
-
 static void *diag204_get_buffer(enum diag204_format fmt, int *pages)
 {
        if (diag204_buf) {
        }
        if (fmt == DIAG204_INFO_SIMPLE) {
                *pages = 1;
-               return diag204_alloc_rbuf();
        } else {/* DIAG204_INFO_EXT */
                *pages = diag204((unsigned long)DIAG204_SUBC_RSI |
                                 (unsigned long)DIAG204_INFO_EXT, 0, NULL);
                if (*pages <= 0)
                        return ERR_PTR(-ENOSYS);
-               else
-                       return diag204_alloc_vbuf(*pages);
        }
+       diag204_buf = __vmalloc_node(array_size(*pages, PAGE_SIZE),
+                                    PAGE_SIZE, GFP_KERNEL, NUMA_NO_NODE,
+                                    __builtin_return_address(0));
+       if (!diag204_buf)
+               return ERR_PTR(-ENOMEM);
+       diag204_buf_pages = *pages;
+       return diag204_buf;
 }
 
 /*
 
 #include <linux/cpu.h>
 #include <linux/seq_file.h>
 #include <linux/debugfs.h>
+#include <linux/vmalloc.h>
 #include <asm/asm-extable.h>
 #include <asm/diag.h>
 #include <asm/trace/diag.h>
        return rp.odd;
 }
 
+/**
+ * diag204() - Issue diagnose 204 call.
+ * @subcode: Subcode of diagnose 204 to be executed.
+ * @size: Size of area in pages which @area points to, if given.
+ * @addr: Vmalloc'ed memory area where the result is written to.
+ *
+ * Execute diagnose 204 with the given subcode and write the result to the
+ * memory area specified with @addr. For subcodes which do not write a
+ * result to memory both @size and @addr must be zero. If @addr is
+ * specified it must be page aligned and must have been allocated with
+ * vmalloc(). Conversion to real / physical addresses will be handled by
+ * this function if required.
+ */
 int diag204(unsigned long subcode, unsigned long size, void *addr)
 {
-       diag_stat_inc(DIAG_STAT_X204);
+       if (addr) {
+               if (WARN_ON_ONCE(!is_vmalloc_addr(addr)))
+                       return -1;
+               if (WARN_ON_ONCE(!IS_ALIGNED((unsigned long)addr, PAGE_SIZE)))
+                       return -1;
+       }
        if ((subcode & DIAG204_SUBCODE_MASK) == DIAG204_SUBC_STIB4)
-               addr = (void *)__pa(addr);
+               addr = (void *)pfn_to_phys(vmalloc_to_pfn(addr));
+       diag_stat_inc(DIAG_STAT_X204);
        size = __diag204(&subcode, size, addr);
        if (subcode)
                return -1;