* @readall:   read a measurement block in a common format
  * @reset:     clear the data in the associated measurement block and
  *             reset its time stamp
- * @align:     align an allocated block so that the hardware can use it
  */
 struct cmb_operations {
        int  (*alloc)  (struct ccw_device *);
        u64  (*read)   (struct ccw_device *, int);
        int  (*readall)(struct ccw_device *, struct cmbdata *);
        void (*reset)  (struct ccw_device *);
-       void *(*align) (void *);
 /* private: */
        struct attribute_group *attr_group;
 };
                        return -EBUSY;
        }
        cmb_data = cdev->private->cmb;
-       hw_block = cmbops->align(cmb_data->hw_block);
+       hw_block = cmb_data->hw_block;
        if (!memcmp(cmb_data->last_block, hw_block, cmb_data->size))
                /* No need to copy. */
                return 0;
                 * Need to reset hw block as well to make the hardware start
                 * from 0 again.
                 */
-               memset(cmbops->align(cmb_data->hw_block), 0, cmb_data->size);
+               memset(cmb_data->hw_block, 0, cmb_data->size);
                cmb_data->last_update = 0;
        }
        cdev->private->cmb_start_time = get_tod_clock();
        cmf_generic_reset(cdev);
 }
 
-static void * align_cmb(void *area)
-{
-       return area;
-}
-
 static struct attribute_group cmf_attr_group;
 
 static struct cmb_operations cmbops_basic = {
        .read   = read_cmb,
        .readall    = readall_cmb,
        .reset      = reset_cmb,
-       .align      = align_cmb,
        .attr_group = &cmf_attr_group,
 };
 
        u32 device_busy_time;
        u32 initial_command_response_time;
        u32 reserved[7];
-};
+} __packed __aligned(64);
 
-/*
- * kmalloc only guarantees 8 byte alignment, but we need cmbe
- * pointers to be naturally aligned. Make sure to allocate
- * enough space for two cmbes.
- */
-static inline struct cmbe *cmbe_align(struct cmbe *c)
-{
-       unsigned long addr;
-       addr = ((unsigned long)c + sizeof (struct cmbe) - sizeof(long)) &
-                                ~(sizeof (struct cmbe) - sizeof(long));
-       return (struct cmbe*)addr;
-}
+static struct kmem_cache *cmbe_cache;
 
 static int alloc_cmbe(struct ccw_device *cdev)
 {
        struct cmbe *cmbe;
        int ret = -ENOMEM;
 
-       cmbe = kzalloc (sizeof (*cmbe) * 2, GFP_KERNEL);
+       cmbe = kmem_cache_zalloc(cmbe_cache, GFP_KERNEL);
        if (!cmbe)
                return ret;
 
-       cmb_data = kzalloc(sizeof(struct cmb_data), GFP_KERNEL);
+       cmb_data = kzalloc(sizeof(*cmb_data), GFP_KERNEL);
        if (!cmb_data)
                goto out_free;
 
        if (!cmb_data->last_block)
                goto out_free;
 
-       cmb_data->size = sizeof(struct cmbe);
+       cmb_data->size = sizeof(*cmbe);
        cmb_data->hw_block = cmbe;
 
        spin_lock(&cmb_area.lock);
        if (cmb_data)
                kfree(cmb_data->last_block);
        kfree(cmb_data);
-       kfree(cmbe);
+       kmem_cache_free(cmbe_cache, cmbe);
+
        return ret;
 }
 
        cdev->private->cmb = NULL;
        if (cmb_data) {
                kfree(cmb_data->last_block);
-               kfree(cmb_data->hw_block);
+               kmem_cache_free(cmbe_cache, cmb_data->hw_block);
        }
        kfree(cmb_data);
 
                return -EINVAL;
        }
        cmb_data = cdev->private->cmb;
-       mba = mme ? (unsigned long) cmbe_align(cmb_data->hw_block) : 0;
+       mba = mme ? (unsigned long) cmb_data->hw_block : 0;
        spin_unlock_irqrestore(cdev->ccwlock, flags);
 
        return set_schib_wait(cdev, mme, 1, mba);
        cmf_generic_reset(cdev);
 }
 
-static void * align_cmbe(void *area)
-{
-       return cmbe_align(area);
-}
-
 static struct attribute_group cmf_attr_group_ext;
 
 static struct cmb_operations cmbops_extended = {
        .read       = read_cmbe,
        .readall    = readall_cmbe,
        .reset      = reset_cmbe,
-       .align      = align_cmbe,
        .attr_group = &cmf_attr_group_ext,
 };
 
        return cmbops->set(cdev, 2);
 }
 
+static int __init init_cmbe(void)
+{
+       cmbe_cache = kmem_cache_create("cmbe_cache", sizeof(struct cmbe),
+                                      __alignof__(struct cmbe), 0, NULL);
+
+       return cmbe_cache ? 0 : -ENOMEM;
+}
+
 static int __init init_cmf(void)
 {
        char *format_string;
-       char *detect_string = "parameter";
+       char *detect_string;
+       int ret;
 
        /*
         * If the user did not give a parameter, see if we are running on a
        case CMF_EXTENDED:
                format_string = "extended";
                cmbops = &cmbops_extended;
+
+               ret = init_cmbe();
+               if (ret)
+                       return ret;
                break;
        default:
-               return 1;
+               return -EINVAL;
        }
        pr_info("Channel measurement facility initialized using format "
                "%s (mode %s)\n", format_string, detect_string);
        return 0;
 }
-
 module_init(init_cmf);