s390/cio: use kmem_cache for extended measurement block allocation
authorSebastian Ott <sebott@linux.vnet.ibm.com>
Mon, 7 Sep 2015 17:53:01 +0000 (19:53 +0200)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Wed, 14 Oct 2015 12:32:04 +0000 (14:32 +0200)
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>
drivers/s390/cio/cmf.c

index 0d1898e51171bf1bf6f09c4ff7a0f7eb7a4acc47..de7074fc6a2cbd96a6bd0e5fca9651a234ce1864 100644 (file)
@@ -113,7 +113,6 @@ module_param(format, bint, 0444);
  * @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 @@ struct cmb_operations {
        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 @@ static int cmf_copy_block(struct ccw_device *cdev)
                        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 @@ static void cmf_generic_reset(struct ccw_device *cdev)
                 * 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 @@ static void reset_cmb(struct ccw_device *cdev)
        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 @@ static struct cmb_operations cmbops_basic = {
        .read   = read_cmb,
        .readall    = readall_cmb,
        .reset      = reset_cmb,
-       .align      = align_cmb,
        .attr_group = &cmf_attr_group,
 };
 
@@ -804,20 +796,9 @@ struct cmbe {
        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 @@ 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;
 
@@ -837,7 +818,7 @@ static int alloc_cmbe(struct ccw_device *cdev)
        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 @@ out_free:
        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 @@ static void free_cmbe(struct ccw_device *cdev)
        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 @@ static int set_cmbe(struct ccw_device *cdev, u32 mme)
                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 @@ static void reset_cmbe(struct ccw_device *cdev)
        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 @@ static struct cmb_operations cmbops_extended = {
        .read       = read_cmbe,
        .readall    = readall_cmbe,
        .reset      = reset_cmbe,
-       .align      = align_cmbe,
        .attr_group = &cmf_attr_group_ext,
 };
 
@@ -1336,10 +1312,19 @@ int cmf_reenable(struct ccw_device *cdev)
        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 @@ static int __init init_cmf(void)
        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);