* @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);