s390/cio: use kmem_cache for extended measurement block allocation

Extended measurement blocks need to be 64 byte aligned. To achieve that
128 bytes for each measurement block are allocated and an align callback
returns a 64 byte aligned address inside this area.

Replace this code with kmem_cache allocations.

Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Reviewed-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c
index 0d1898e..de7074f 100644
--- a/drivers/s390/cio/cmf.c
+++ b/drivers/s390/cio/cmf.c
@@ -113,7 +113,6 @@
  * @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 *);
@@ -122,7 +121,6 @@
 	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;
 };
@@ -321,7 +319,7 @@
 			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;
@@ -432,7 +430,7 @@
 		 * 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();
@@ -755,11 +753,6 @@
 	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 = {
@@ -769,7 +762,6 @@
 	.read	= read_cmb,
 	.readall    = readall_cmb,
 	.reset	    = reset_cmb,
-	.align	    = align_cmb,
 	.attr_group = &cmf_attr_group,
 };
 
@@ -804,20 +796,9 @@
 	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)
 {
@@ -825,11 +806,11 @@
 	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;
 
@@ -837,7 +818,7 @@
 	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);
@@ -864,7 +845,8 @@
 	if (cmb_data)
 		kfree(cmb_data->last_block);
 	kfree(cmb_data);
-	kfree(cmbe);
+	kmem_cache_free(cmbe_cache, cmbe);
+
 	return ret;
 }
 
@@ -878,7 +860,7 @@
 	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);
 
@@ -902,7 +884,7 @@
 		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);
@@ -1027,11 +1009,6 @@
 	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 = {
@@ -1041,7 +1018,6 @@
 	.read	    = read_cmbe,
 	.readall    = readall_cmbe,
 	.reset	    = reset_cmbe,
-	.align	    = align_cmbe,
 	.attr_group = &cmf_attr_group_ext,
 };
 
@@ -1336,10 +1312,19 @@
 	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
@@ -1365,15 +1350,18 @@
 	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);