diff options
author | Peter Oberparleiter <oberpar@linux.ibm.com> | 2024-03-26 17:03:22 +0100 |
---|---|---|
committer | Alexander Gordeev <agordeev@linux.ibm.com> | 2024-04-12 16:11:29 +0200 |
commit | 2dc8903af775ecd51e42c0a2e7afa0e98d1bde45 (patch) | |
tree | 7f58881e6e22ea18b84b5d0b9f94ef3b89995ed9 /drivers/s390 | |
parent | b4691baaeef07bdc4c3524a0702d7dd6899610b4 (diff) | |
download | linux-stable-2dc8903af775ecd51e42c0a2e7afa0e98d1bde45.tar.gz linux-stable-2dc8903af775ecd51e42c0a2e7afa0e98d1bde45.tar.bz2 linux-stable-2dc8903af775ecd51e42c0a2e7afa0e98d1bde45.zip |
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>
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/cio/chp.c | 68 | ||||
-rw-r--r-- | drivers/s390/cio/chp.h | 1 | ||||
-rw-r--r-- | drivers/s390/cio/chsc.c | 24 | ||||
-rw-r--r-- | drivers/s390/cio/chsc.h | 5 | ||||
-rw-r--r-- | drivers/s390/cio/css.h | 3 |
5 files changed, 69 insertions, 32 deletions
diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c index e4a9ce5cacbb..fd7d34ed6ea9 100644 --- a/drivers/s390/cio/chp.c +++ b/drivers/s390/cio/chp.c @@ -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) -{ - void *area; - struct cmg_entry *entry, reference_buf; - int idx; - - if (chpid.id < CSS_CUES_PER_PAGE) { - area = css->cub[0]; - idx = chpid.id; - } else { - area = css->cub[1]; - idx = chpid.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]); -} - -static ssize_t measurement_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) +static ssize_t chp_measurement_copy_block(void *buf, loff_t off, size_t count, + struct kobject *kobj, bool extended) { struct channel_path *chp; struct channel_subsystem *css; struct device *device; unsigned int size; + void *area, *entry; + int id, idx; device = kobj_to_dev(kobj); chp = to_channelpath(device); css = to_css(chp->dev.parent); + id = chp->chpid.id; - size = sizeof(struct cmg_entry); + 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 { + size = sizeof(struct cmg_entry); + area = css->cub[id / CSS_CUES_PER_PAGE]; + idx = id % CSS_CUES_PER_PAGE; + } + entry = area + (idx * size); /* 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; + + 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) +{ + 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); diff --git a/drivers/s390/cio/chp.h b/drivers/s390/cio/chp.h index 7ee9eba0abcb..1241033ccd62 100644 --- a/drivers/s390/cio/chp.h +++ b/drivers/s390/cio/chp.h @@ -51,6 +51,7 @@ struct channel_path { /* Channel-measurement related stuff: */ int cmg; int shared; + int extended; struct cmg_chars cmg_chars; }; diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 3344fa996ec4..f2f4c7e19048 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -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; diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h index 03602295f335..24cd65dbc5a7 100644 --- a/drivers/s390/cio/chsc.h +++ b/drivers/s390/cio/chsc.h @@ -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; diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index aca11dacb224..c2b175592bb7 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h @@ -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; }; |