mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-17 18:56:24 +00:00
s390/cio: export extended channel-path-measurement data
Add a per-CHPID binary sysfs attribute named "ext_measurement" that provides access to extended channel-path-measurement data for the associated channel path. Note that while not all channel-paths provide extended measurement data this attribute is created unconditionally for all channel paths because channel-path measurement capabilities might change during run-time. Reading from the attribute will only return data for channel-paths that support extended measurement data. Example: $ echo 1 > /sys/devices/css0/cm_enable $ xxd /sys/devices/css0/chp0.32/ext_measurement 00000000: 53e0 8002 0000 0095 0000 0000 59cc e034 S...........Y..4 00000010: 38b8 cc45 0000 0000 0000 0000 3e24 fe94 8..E........>$.. 00000020: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000030: 0000 0000 0000 0000 0000 0000 0000 0000 ................ Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com> Tested-by: Vineeth Vijayan <vneethv@linux.ibm.com> Acked-by: Heiko Carstens <hca@linux.ibm.com> Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com> Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
This commit is contained in:
parent
b4691baaee
commit
2dc8903af7
@ -144,55 +144,65 @@ static ssize_t measurement_chars_read(struct file *filp, struct kobject *kobj,
|
||||
}
|
||||
static BIN_ATTR_ADMIN_RO(measurement_chars, sizeof(struct cmg_chars));
|
||||
|
||||
static void chp_measurement_copy_block(struct cmg_entry *buf,
|
||||
struct channel_subsystem *css,
|
||||
struct chp_id chpid)
|
||||
static ssize_t chp_measurement_copy_block(void *buf, loff_t off, size_t count,
|
||||
struct kobject *kobj, bool extended)
|
||||
{
|
||||
void *area;
|
||||
struct cmg_entry *entry, reference_buf;
|
||||
int idx;
|
||||
struct channel_path *chp;
|
||||
struct channel_subsystem *css;
|
||||
struct device *device;
|
||||
unsigned int size;
|
||||
void *area, *entry;
|
||||
int id, idx;
|
||||
|
||||
if (chpid.id < CSS_CUES_PER_PAGE) {
|
||||
area = css->cub[0];
|
||||
idx = chpid.id;
|
||||
device = kobj_to_dev(kobj);
|
||||
chp = to_channelpath(device);
|
||||
css = to_css(chp->dev.parent);
|
||||
id = chp->chpid.id;
|
||||
|
||||
if (extended) {
|
||||
/* Check if extended measurement data is available. */
|
||||
if (!chp->extended)
|
||||
return 0;
|
||||
|
||||
size = sizeof(struct cmg_ext_entry);
|
||||
area = css->ecub[id / CSS_ECUES_PER_PAGE];
|
||||
idx = id % CSS_ECUES_PER_PAGE;
|
||||
} else {
|
||||
area = css->cub[1];
|
||||
idx = chpid.id - CSS_CUES_PER_PAGE;
|
||||
size = sizeof(struct cmg_entry);
|
||||
area = css->cub[id / CSS_CUES_PER_PAGE];
|
||||
idx = id % CSS_CUES_PER_PAGE;
|
||||
}
|
||||
entry = area + (idx * sizeof(struct cmg_entry));
|
||||
do {
|
||||
memcpy(buf, entry, sizeof(*entry));
|
||||
memcpy(&reference_buf, entry, sizeof(*entry));
|
||||
} while (reference_buf.values[0] != buf->values[0]);
|
||||
entry = area + (idx * size);
|
||||
|
||||
/* Only allow single reads. */
|
||||
if (off || count < size)
|
||||
return 0;
|
||||
|
||||
memcpy(buf, entry, size);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t measurement_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct channel_path *chp;
|
||||
struct channel_subsystem *css;
|
||||
struct device *device;
|
||||
unsigned int size;
|
||||
|
||||
device = kobj_to_dev(kobj);
|
||||
chp = to_channelpath(device);
|
||||
css = to_css(chp->dev.parent);
|
||||
|
||||
size = sizeof(struct cmg_entry);
|
||||
|
||||
/* Only allow single reads. */
|
||||
if (off || count < size)
|
||||
return 0;
|
||||
chp_measurement_copy_block((struct cmg_entry *)buf, css, chp->chpid);
|
||||
count = size;
|
||||
return count;
|
||||
return chp_measurement_copy_block(buf, off, count, kobj, false);
|
||||
}
|
||||
static BIN_ATTR_ADMIN_RO(measurement, sizeof(struct cmg_entry));
|
||||
|
||||
static ssize_t ext_measurement_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
return chp_measurement_copy_block(buf, off, count, kobj, true);
|
||||
}
|
||||
static BIN_ATTR_ADMIN_RO(ext_measurement, sizeof(struct cmg_ext_entry));
|
||||
|
||||
static struct bin_attribute *measurement_attrs[] = {
|
||||
&bin_attr_measurement_chars,
|
||||
&bin_attr_measurement,
|
||||
&bin_attr_ext_measurement,
|
||||
NULL,
|
||||
};
|
||||
BIN_ATTRIBUTE_GROUPS(measurement);
|
||||
|
@ -51,6 +51,7 @@ struct channel_path {
|
||||
/* Channel-measurement related stuff: */
|
||||
int cmg;
|
||||
int shared;
|
||||
int extended;
|
||||
struct cmg_chars cmg_chars;
|
||||
};
|
||||
|
||||
|
@ -871,11 +871,14 @@ int __chsc_do_secm(struct channel_subsystem *css, int enable)
|
||||
struct {
|
||||
struct chsc_header request;
|
||||
u32 operation_code : 2;
|
||||
u32 : 30;
|
||||
u32 : 1;
|
||||
u32 e : 1;
|
||||
u32 : 28;
|
||||
u32 key : 4;
|
||||
u32 : 28;
|
||||
dma64_t cub[CSS_NUM_CUB_PAGES];
|
||||
u32 reserved[13];
|
||||
dma64_t ecub[CSS_NUM_ECUB_PAGES];
|
||||
u32 reserved[5];
|
||||
struct chsc_header response;
|
||||
u32 status : 8;
|
||||
u32 : 4;
|
||||
@ -892,9 +895,12 @@ int __chsc_do_secm(struct channel_subsystem *css, int enable)
|
||||
secm_area->request.code = 0x0016;
|
||||
|
||||
secm_area->key = PAGE_DEFAULT_KEY >> 4;
|
||||
secm_area->e = 1;
|
||||
|
||||
for (i = 0; i < CSS_NUM_CUB_PAGES; i++)
|
||||
secm_area->cub[i] = (__force dma64_t)virt_to_dma32(css->cub[i]);
|
||||
for (i = 0; i < CSS_NUM_ECUB_PAGES; i++)
|
||||
secm_area->ecub[i] = virt_to_dma64(css->ecub[i]);
|
||||
|
||||
secm_area->operation_code = enable ? 0 : 1;
|
||||
|
||||
@ -929,6 +935,11 @@ static int cub_alloc(struct channel_subsystem *css)
|
||||
if (!css->cub[i])
|
||||
return -ENOMEM;
|
||||
}
|
||||
for (i = 0; i < CSS_NUM_ECUB_PAGES; i++) {
|
||||
css->ecub[i] = (void *)get_zeroed_page(GFP_KERNEL);
|
||||
if (!css->ecub[i])
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -941,6 +952,10 @@ static void cub_free(struct channel_subsystem *css)
|
||||
free_page((unsigned long)css->cub[i]);
|
||||
css->cub[i] = NULL;
|
||||
}
|
||||
for (i = 0; i < CSS_NUM_ECUB_PAGES; i++) {
|
||||
free_page((unsigned long)css->ecub[i]);
|
||||
css->ecub[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
@ -1067,7 +1082,8 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp)
|
||||
u32 zeroes2;
|
||||
u32 not_valid : 1;
|
||||
u32 shared : 1;
|
||||
u32 : 22;
|
||||
u32 extended : 1;
|
||||
u32 : 21;
|
||||
u32 chpid : 8;
|
||||
u32 cmcv : 5;
|
||||
u32 : 11;
|
||||
@ -1079,6 +1095,7 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp)
|
||||
|
||||
chp->shared = -1;
|
||||
chp->cmg = -1;
|
||||
chp->extended = 0;
|
||||
|
||||
if (!css_chsc_characteristics.scmc || !css_chsc_characteristics.secm)
|
||||
return -EINVAL;
|
||||
@ -1108,6 +1125,7 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp)
|
||||
|
||||
chp->cmg = scmc_area->cmg;
|
||||
chp->shared = scmc_area->shared;
|
||||
chp->extended = scmc_area->extended;
|
||||
if (chp->cmg != 2 && chp->cmg != 3) {
|
||||
/* No cmg-dependent data. */
|
||||
goto out;
|
||||
|
@ -22,6 +22,11 @@ struct cmg_entry {
|
||||
u32 values[NR_MEASUREMENT_ENTRIES];
|
||||
};
|
||||
|
||||
#define NR_EXT_MEASUREMENT_ENTRIES 16
|
||||
struct cmg_ext_entry {
|
||||
u32 values[NR_EXT_MEASUREMENT_ENTRIES];
|
||||
};
|
||||
|
||||
struct channel_path_desc_fmt1 {
|
||||
u8 flags;
|
||||
u8 lsn;
|
||||
|
@ -40,6 +40,8 @@
|
||||
|
||||
#define CSS_NUM_CUB_PAGES 2
|
||||
#define CSS_CUES_PER_PAGE 128
|
||||
#define CSS_NUM_ECUB_PAGES 4
|
||||
#define CSS_ECUES_PER_PAGE 64
|
||||
|
||||
/*
|
||||
* Conditions used to specify which subchannels need evaluation
|
||||
@ -130,6 +132,7 @@ struct channel_subsystem {
|
||||
/* channel measurement related */
|
||||
int cm_enabled;
|
||||
void *cub[CSS_NUM_CUB_PAGES];
|
||||
void *ecub[CSS_NUM_ECUB_PAGES];
|
||||
/* for orphaned ccw devices */
|
||||
struct subchannel *pseudo_subchannel;
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user