Skip to content

Commit b4bc47e

Browse files
committed
Merge: s390/cio: rework channel-utilization-block handling
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/5955 JIRA: https://issues.redhat.com/browse/RHEL-50790 Tested-By: IBM Build-Info: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=66121128 Commits: ``` a817d98 b4691ba 2dc8903 5e6bb10 0f987e6 2f4b3b8 ``` Signed-off-by: Mete Durlu <mdurlu@redhat.com> Approved-by: Steve Best <sbest@redhat.com> Approved-by: Tony Camuso <tcamuso@redhat.com> Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> Merged-by: Rado Vrbovsky <rvrbovsk@redhat.com>
2 parents fb9d324 + 3e76cff commit b4bc47e

File tree

5 files changed

+202
-98
lines changed

5 files changed

+202
-98
lines changed

drivers/s390/cio/chp.c

Lines changed: 90 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,9 @@ static int s390_vary_chpid(struct chp_id chpid, int on)
127127
/*
128128
* Channel measurement related functions
129129
*/
130-
static ssize_t chp_measurement_chars_read(struct file *filp,
131-
struct kobject *kobj,
132-
struct bin_attribute *bin_attr,
133-
char *buf, loff_t off, size_t count)
130+
static ssize_t measurement_chars_read(struct file *filp, struct kobject *kobj,
131+
struct bin_attribute *bin_attr,
132+
char *buf, loff_t off, size_t count)
134133
{
135134
struct channel_path *chp;
136135
struct device *device;
@@ -143,87 +142,92 @@ static ssize_t chp_measurement_chars_read(struct file *filp,
143142
return memory_read_from_buffer(buf, count, &off, &chp->cmg_chars,
144143
sizeof(chp->cmg_chars));
145144
}
145+
static BIN_ATTR_ADMIN_RO(measurement_chars, sizeof(struct cmg_chars));
146146

147-
static const struct bin_attribute chp_measurement_chars_attr = {
148-
.attr = {
149-
.name = "measurement_chars",
150-
.mode = S_IRUSR,
151-
},
152-
.size = sizeof(struct cmg_chars),
153-
.read = chp_measurement_chars_read,
154-
};
155-
156-
static void chp_measurement_copy_block(struct cmg_entry *buf,
157-
struct channel_subsystem *css,
158-
struct chp_id chpid)
147+
static ssize_t measurement_chars_full_read(struct file *filp,
148+
struct kobject *kobj,
149+
struct bin_attribute *bin_attr,
150+
char *buf, loff_t off, size_t count)
159151
{
160-
void *area;
161-
struct cmg_entry *entry, reference_buf;
162-
int idx;
152+
struct channel_path *chp = to_channelpath(kobj_to_dev(kobj));
163153

164-
if (chpid.id < 128) {
165-
area = css->cub_addr1;
166-
idx = chpid.id;
167-
} else {
168-
area = css->cub_addr2;
169-
idx = chpid.id - 128;
170-
}
171-
entry = area + (idx * sizeof(struct cmg_entry));
172-
do {
173-
memcpy(buf, entry, sizeof(*entry));
174-
memcpy(&reference_buf, entry, sizeof(*entry));
175-
} while (reference_buf.values[0] != buf->values[0]);
154+
return memory_read_from_buffer(buf, count, &off, &chp->cmcb,
155+
sizeof(chp->cmcb));
176156
}
157+
static BIN_ATTR_ADMIN_RO(measurement_chars_full, sizeof(struct cmg_cmcb));
177158

178-
static ssize_t chp_measurement_read(struct file *filp, struct kobject *kobj,
179-
struct bin_attribute *bin_attr,
180-
char *buf, loff_t off, size_t count)
159+
static ssize_t chp_measurement_copy_block(void *buf, loff_t off, size_t count,
160+
struct kobject *kobj, bool extended)
181161
{
182162
struct channel_path *chp;
183163
struct channel_subsystem *css;
184164
struct device *device;
185165
unsigned int size;
166+
void *area, *entry;
167+
int id, idx;
186168

187169
device = kobj_to_dev(kobj);
188170
chp = to_channelpath(device);
189171
css = to_css(chp->dev.parent);
172+
id = chp->chpid.id;
190173

191-
size = sizeof(struct cmg_entry);
174+
if (extended) {
175+
/* Check if extended measurement data is available. */
176+
if (!chp->extended)
177+
return 0;
178+
179+
size = sizeof(struct cmg_ext_entry);
180+
area = css->ecub[id / CSS_ECUES_PER_PAGE];
181+
idx = id % CSS_ECUES_PER_PAGE;
182+
} else {
183+
size = sizeof(struct cmg_entry);
184+
area = css->cub[id / CSS_CUES_PER_PAGE];
185+
idx = id % CSS_CUES_PER_PAGE;
186+
}
187+
entry = area + (idx * size);
192188

193189
/* Only allow single reads. */
194190
if (off || count < size)
195191
return 0;
196-
chp_measurement_copy_block((struct cmg_entry *)buf, css, chp->chpid);
197-
count = size;
198-
return count;
192+
193+
memcpy(buf, entry, size);
194+
195+
return size;
196+
}
197+
198+
static ssize_t measurement_read(struct file *filp, struct kobject *kobj,
199+
struct bin_attribute *bin_attr,
200+
char *buf, loff_t off, size_t count)
201+
{
202+
return chp_measurement_copy_block(buf, off, count, kobj, false);
203+
}
204+
static BIN_ATTR_ADMIN_RO(measurement, sizeof(struct cmg_entry));
205+
206+
static ssize_t ext_measurement_read(struct file *filp, struct kobject *kobj,
207+
struct bin_attribute *bin_attr,
208+
char *buf, loff_t off, size_t count)
209+
{
210+
return chp_measurement_copy_block(buf, off, count, kobj, true);
199211
}
212+
static BIN_ATTR_ADMIN_RO(ext_measurement, sizeof(struct cmg_ext_entry));
200213

201-
static const struct bin_attribute chp_measurement_attr = {
202-
.attr = {
203-
.name = "measurement",
204-
.mode = S_IRUSR,
205-
},
206-
.size = sizeof(struct cmg_entry),
207-
.read = chp_measurement_read,
214+
static struct bin_attribute *measurement_attrs[] = {
215+
&bin_attr_measurement_chars,
216+
&bin_attr_measurement_chars_full,
217+
&bin_attr_measurement,
218+
&bin_attr_ext_measurement,
219+
NULL,
208220
};
221+
BIN_ATTRIBUTE_GROUPS(measurement);
209222

210223
void chp_remove_cmg_attr(struct channel_path *chp)
211224
{
212-
device_remove_bin_file(&chp->dev, &chp_measurement_chars_attr);
213-
device_remove_bin_file(&chp->dev, &chp_measurement_attr);
225+
device_remove_groups(&chp->dev, measurement_groups);
214226
}
215227

216228
int chp_add_cmg_attr(struct channel_path *chp)
217229
{
218-
int ret;
219-
220-
ret = device_create_bin_file(&chp->dev, &chp_measurement_chars_attr);
221-
if (ret)
222-
return ret;
223-
ret = device_create_bin_file(&chp->dev, &chp_measurement_attr);
224-
if (ret)
225-
device_remove_bin_file(&chp->dev, &chp_measurement_chars_attr);
226-
return ret;
230+
return device_add_groups(&chp->dev, measurement_groups);
227231
}
228232

229233
/*
@@ -401,6 +405,35 @@ static ssize_t chp_esc_show(struct device *dev,
401405
}
402406
static DEVICE_ATTR(esc, 0444, chp_esc_show, NULL);
403407

408+
static char apply_max_suffix(unsigned long *value, unsigned long base)
409+
{
410+
static char suffixes[] = { 0, 'K', 'M', 'G', 'T' };
411+
int i;
412+
413+
for (i = 0; i < ARRAY_SIZE(suffixes) - 1; i++) {
414+
if (*value < base || *value % base != 0)
415+
break;
416+
*value /= base;
417+
}
418+
419+
return suffixes[i];
420+
}
421+
422+
static ssize_t speed_bps_show(struct device *dev,
423+
struct device_attribute *attr, char *buf)
424+
{
425+
struct channel_path *chp = to_channelpath(dev);
426+
unsigned long speed = chp->speed;
427+
char suffix;
428+
429+
suffix = apply_max_suffix(&speed, 1000);
430+
431+
return suffix ? sysfs_emit(buf, "%lu%c\n", speed, suffix) :
432+
sysfs_emit(buf, "%lu\n", speed);
433+
}
434+
435+
static DEVICE_ATTR_RO(speed_bps);
436+
404437
static ssize_t util_string_read(struct file *filp, struct kobject *kobj,
405438
struct bin_attribute *attr, char *buf,
406439
loff_t off, size_t count)
@@ -432,6 +465,7 @@ static struct attribute *chp_attrs[] = {
432465
&dev_attr_chid.attr,
433466
&dev_attr_chid_external.attr,
434467
&dev_attr_esc.attr,
468+
&dev_attr_speed_bps.attr,
435469
NULL,
436470
};
437471
static struct attribute_group chp_attr_group = {

drivers/s390/cio/chp.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,10 @@ struct channel_path {
5151
/* Channel-measurement related stuff: */
5252
int cmg;
5353
int shared;
54+
int extended;
55+
unsigned long speed;
5456
struct cmg_chars cmg_chars;
57+
struct cmg_cmcb cmcb;
5558
};
5659

5760
/* Return channel_path struct for given chpid. */

drivers/s390/cio/chsc.c

Lines changed: 77 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -857,22 +857,22 @@ int __chsc_do_secm(struct channel_subsystem *css, int enable)
857857
struct {
858858
struct chsc_header request;
859859
u32 operation_code : 2;
860-
u32 : 30;
860+
u32 : 1;
861+
u32 e : 1;
862+
u32 : 28;
861863
u32 key : 4;
862864
u32 : 28;
863-
u32 zeroes1;
864-
dma32_t cub_addr1;
865-
u32 zeroes2;
866-
dma32_t cub_addr2;
867-
u32 reserved[13];
865+
dma64_t cub[CSS_NUM_CUB_PAGES];
866+
dma64_t ecub[CSS_NUM_ECUB_PAGES];
867+
u32 reserved[5];
868868
struct chsc_header response;
869869
u32 status : 8;
870870
u32 : 4;
871871
u32 fmt : 4;
872872
u32 : 16;
873-
} *secm_area;
873+
} __packed *secm_area;
874874
unsigned long flags;
875-
int ret, ccode;
875+
int ret, ccode, i;
876876

877877
spin_lock_irqsave(&chsc_page_lock, flags);
878878
memset(chsc_page, 0, PAGE_SIZE);
@@ -881,8 +881,12 @@ int __chsc_do_secm(struct channel_subsystem *css, int enable)
881881
secm_area->request.code = 0x0016;
882882

883883
secm_area->key = PAGE_DEFAULT_KEY >> 4;
884-
secm_area->cub_addr1 = virt_to_dma32(css->cub_addr1);
885-
secm_area->cub_addr2 = virt_to_dma32(css->cub_addr2);
884+
secm_area->e = 1;
885+
886+
for (i = 0; i < CSS_NUM_CUB_PAGES; i++)
887+
secm_area->cub[i] = (__force dma64_t)virt_to_dma32(css->cub[i]);
888+
for (i = 0; i < CSS_NUM_ECUB_PAGES; i++)
889+
secm_area->ecub[i] = virt_to_dma64(css->ecub[i]);
886890

887891
secm_area->operation_code = enable ? 0 : 1;
888892

@@ -908,19 +912,47 @@ int __chsc_do_secm(struct channel_subsystem *css, int enable)
908912
return ret;
909913
}
910914

915+
static int cub_alloc(struct channel_subsystem *css)
916+
{
917+
int i;
918+
919+
for (i = 0; i < CSS_NUM_CUB_PAGES; i++) {
920+
css->cub[i] = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
921+
if (!css->cub[i])
922+
return -ENOMEM;
923+
}
924+
for (i = 0; i < CSS_NUM_ECUB_PAGES; i++) {
925+
css->ecub[i] = (void *)get_zeroed_page(GFP_KERNEL);
926+
if (!css->ecub[i])
927+
return -ENOMEM;
928+
}
929+
930+
return 0;
931+
}
932+
933+
static void cub_free(struct channel_subsystem *css)
934+
{
935+
int i;
936+
937+
for (i = 0; i < CSS_NUM_CUB_PAGES; i++) {
938+
free_page((unsigned long)css->cub[i]);
939+
css->cub[i] = NULL;
940+
}
941+
for (i = 0; i < CSS_NUM_ECUB_PAGES; i++) {
942+
free_page((unsigned long)css->ecub[i]);
943+
css->ecub[i] = NULL;
944+
}
945+
}
946+
911947
int
912948
chsc_secm(struct channel_subsystem *css, int enable)
913949
{
914950
int ret;
915951

916952
if (enable && !css->cm_enabled) {
917-
css->cub_addr1 = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
918-
css->cub_addr2 = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
919-
if (!css->cub_addr1 || !css->cub_addr2) {
920-
free_page((unsigned long)css->cub_addr1);
921-
free_page((unsigned long)css->cub_addr2);
922-
return -ENOMEM;
923-
}
953+
ret = cub_alloc(css);
954+
if (ret)
955+
goto out;
924956
}
925957
ret = __chsc_do_secm(css, enable);
926958
if (!ret) {
@@ -934,10 +966,11 @@ chsc_secm(struct channel_subsystem *css, int enable)
934966
} else
935967
chsc_remove_cmg_attr(css);
936968
}
937-
if (!css->cm_enabled) {
938-
free_page((unsigned long)css->cub_addr1);
939-
free_page((unsigned long)css->cub_addr2);
940-
}
969+
970+
out:
971+
if (!css->cm_enabled)
972+
cub_free(css);
973+
941974
return ret;
942975
}
943976

@@ -1019,6 +1052,18 @@ chsc_initialize_cmg_chars(struct channel_path *chp, u8 cmcv,
10191052
}
10201053
}
10211054

1055+
static unsigned long scmc_get_speed(u32 s, u32 p)
1056+
{
1057+
unsigned long speed = s;
1058+
1059+
if (!p)
1060+
p = 8;
1061+
while (p--)
1062+
speed *= 10;
1063+
1064+
return speed;
1065+
}
1066+
10221067
int chsc_get_channel_measurement_chars(struct channel_path *chp)
10231068
{
10241069
unsigned long flags;
@@ -1033,20 +1078,13 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp)
10331078
u32 zeroes1;
10341079
struct chsc_header response;
10351080
u32 zeroes2;
1036-
u32 not_valid : 1;
1037-
u32 shared : 1;
1038-
u32 : 22;
1039-
u32 chpid : 8;
1040-
u32 cmcv : 5;
1041-
u32 : 11;
1042-
u32 cmgq : 8;
1043-
u32 cmg : 8;
1044-
u32 zeroes3;
1045-
u32 data[NR_MEASUREMENT_CHARS];
1081+
struct cmg_cmcb cmcb;
10461082
} *scmc_area;
10471083

10481084
chp->shared = -1;
10491085
chp->cmg = -1;
1086+
chp->extended = 0;
1087+
chp->speed = 0;
10501088

10511089
if (!css_chsc_characteristics.scmc || !css_chsc_characteristics.secm)
10521090
return -EINVAL;
@@ -1071,17 +1109,16 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp)
10711109
scmc_area->response.code);
10721110
goto out;
10731111
}
1074-
if (scmc_area->not_valid)
1112+
chp->cmcb = scmc_area->cmcb;
1113+
if (scmc_area->cmcb.not_valid)
10751114
goto out;
10761115

1077-
chp->cmg = scmc_area->cmg;
1078-
chp->shared = scmc_area->shared;
1079-
if (chp->cmg != 2 && chp->cmg != 3) {
1080-
/* No cmg-dependent data. */
1081-
goto out;
1082-
}
1083-
chsc_initialize_cmg_chars(chp, scmc_area->cmcv,
1084-
(struct cmg_chars *) &scmc_area->data);
1116+
chp->cmg = scmc_area->cmcb.cmg;
1117+
chp->shared = scmc_area->cmcb.shared;
1118+
chp->extended = scmc_area->cmcb.extended;
1119+
chp->speed = scmc_get_speed(scmc_area->cmcb.cmgs, scmc_area->cmcb.cmgp);
1120+
chsc_initialize_cmg_chars(chp, scmc_area->cmcb.cmcv,
1121+
(struct cmg_chars *)&scmc_area->cmcb.data);
10851122
out:
10861123
spin_unlock_irqrestore(&chsc_page_lock, flags);
10871124
return ret;

0 commit comments

Comments
 (0)