s390/cio: export CHPID operating speed

Add a per-CHPID sysfs attribute named "speed_bps" that provides the
operating speed of the associated channel path in bits per second,
or 0 if the operating speed is not available.

Example:

$ cat /sys/devices/css0/chp0.32/speed_bps
32G

Reviewed-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:
Peter Oberparleiter 2024-03-26 17:03:24 +01:00 committed by Alexander Gordeev
parent 5e6bb10ee5
commit 0f987e6caa
3 changed files with 49 additions and 2 deletions

View File

@ -392,6 +392,35 @@ static ssize_t chp_esc_show(struct device *dev,
}
static DEVICE_ATTR(esc, 0444, chp_esc_show, NULL);
static char apply_max_suffix(unsigned long *value, unsigned long base)
{
static char suffixes[] = { 0, 'K', 'M', 'G', 'T' };
int i;
for (i = 0; i < ARRAY_SIZE(suffixes) - 1; i++) {
if (*value < base || *value % base != 0)
break;
*value /= base;
}
return suffixes[i];
}
static ssize_t speed_bps_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct channel_path *chp = to_channelpath(dev);
unsigned long speed = chp->speed;
char suffix;
suffix = apply_max_suffix(&speed, 1000);
return suffix ? sysfs_emit(buf, "%lu%c\n", speed, suffix) :
sysfs_emit(buf, "%lu\n", speed);
}
static DEVICE_ATTR_RO(speed_bps);
static ssize_t util_string_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr, char *buf,
loff_t off, size_t count)
@ -423,6 +452,7 @@ static struct attribute *chp_attrs[] = {
&dev_attr_chid.attr,
&dev_attr_chid_external.attr,
&dev_attr_esc.attr,
&dev_attr_speed_bps.attr,
NULL,
};
static struct attribute_group chp_attr_group = {

View File

@ -52,6 +52,7 @@ struct channel_path {
int cmg;
int shared;
int extended;
unsigned long speed;
struct cmg_chars cmg_chars;
};

View File

@ -1066,6 +1066,18 @@ chsc_initialize_cmg_chars(struct channel_path *chp, u8 cmcv,
}
}
static unsigned long scmc_get_speed(u32 s, u32 p)
{
unsigned long speed = s;
if (!p)
p = 8;
while (p--)
speed *= 10;
return speed;
}
int chsc_get_channel_measurement_chars(struct channel_path *chp)
{
unsigned long flags;
@ -1086,16 +1098,19 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp)
u32 : 21;
u32 chpid : 8;
u32 cmcv : 5;
u32 : 11;
u32 : 7;
u32 cmgp : 4;
u32 cmgq : 8;
u32 cmg : 8;
u32 zeroes3;
u32 : 16;
u32 cmgs : 16;
u32 data[NR_MEASUREMENT_CHARS];
} *scmc_area;
chp->shared = -1;
chp->cmg = -1;
chp->extended = 0;
chp->speed = 0;
if (!css_chsc_characteristics.scmc || !css_chsc_characteristics.secm)
return -EINVAL;
@ -1126,6 +1141,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;
chp->speed = scmc_get_speed(scmc_area->cmgs, scmc_area->cmgp);
chsc_initialize_cmg_chars(chp, scmc_area->cmcv,
(struct cmg_chars *) &scmc_area->data);
out: