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