s390/cio: export extended channel-path-measurement data
authorPeter Oberparleiter <oberpar@linux.ibm.com>
Tue, 26 Mar 2024 16:03:22 +0000 (17:03 +0100)
committerAlexander Gordeev <agordeev@linux.ibm.com>
Fri, 12 Apr 2024 14:11:29 +0000 (16:11 +0200)
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>
drivers/s390/cio/chp.c
drivers/s390/cio/chp.h
drivers/s390/cio/chsc.c
drivers/s390/cio/chsc.h
drivers/s390/cio/css.h

index e4a9ce5..fd7d34e 100644 (file)
@@ -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);
index 7ee9eba..1241033 100644 (file)
@@ -51,6 +51,7 @@ struct channel_path {
        /* Channel-measurement related stuff: */
        int cmg;
        int shared;
+       int extended;
        struct cmg_chars cmg_chars;
 };
 
index 3344fa9..f2f4c7e 100644 (file)
@@ -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;
index 0360229..24cd65d 100644 (file)
@@ -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;
index aca11da..c2b1755 100644 (file)
@@ -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;
 };