Skip to content

Commit 5951f20

Browse files
author
Mete Durlu
committed
s390/diag324: Retrieve power readings via diag 0x324
JIRA: https://issues.redhat.com/browse/RHEL-72676 Conflicts: Minor merge conflict - no functional change commit 90e6f19 Author: Sumanth Korikkar <[email protected]> Date: Thu Dec 12 17:17:19 2024 +0100 s390/diag324: Retrieve power readings via diag 0x324 Retrieve electrical power readings for resources in a computing environment via diag 0x324. diag 0x324 stores the power readings in the power information block (pib). Provide power readings from pib via diag324 ioctl interface. diag324 ioctl provides new pib to the user only if the threshold time has passed since the last call. Otherwise, cache data is returned. When there are no active readers, cleanup of pib buffer is performed. Reviewed-by: Heiko Carstens <[email protected]> Signed-off-by: Sumanth Korikkar <[email protected]> Signed-off-by: Alexander Gordeev <[email protected]> Signed-off-by: Mete Durlu <[email protected]>
1 parent bc261fe commit 5951f20

File tree

11 files changed

+277
-2
lines changed

11 files changed

+277
-2
lines changed

arch/s390/include/asm/diag.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ enum diag_stat_enum {
3737
DIAG_STAT_X308,
3838
DIAG_STAT_X318,
3939
DIAG_STAT_X320,
40+
DIAG_STAT_X324,
4041
DIAG_STAT_X49C,
4142
DIAG_STAT_X500,
4243
NR_DIAG_STAT

arch/s390/include/asm/sclp.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ struct sclp_info {
9393
unsigned char has_gisaf : 1;
9494
unsigned char has_diag318 : 1;
9595
unsigned char has_diag320 : 1;
96+
unsigned char has_diag324 : 1;
9697
unsigned char has_sipl : 1;
9798
unsigned char has_sipl_eckd : 1;
9899
unsigned char has_dirq : 1;

arch/s390/include/uapi/asm/diag.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
2+
/*
3+
* Diag ioctls and its associated structures definitions.
4+
*
5+
* Copyright IBM Corp. 2024
6+
*/
7+
8+
#ifndef __S390_UAPI_ASM_DIAG_H
9+
#define __S390_UAPI_ASM_DIAG_H
10+
11+
#include <linux/types.h>
12+
13+
#define DIAG_MAGIC_STR 'D'
14+
15+
struct diag324_pib {
16+
__u64 address;
17+
__u64 sequence;
18+
};
19+
20+
/* Diag ioctl definitions */
21+
#define DIAG324_GET_PIBBUF _IOWR(DIAG_MAGIC_STR, 0x77, struct diag324_pib)
22+
#define DIAG324_GET_PIBLEN _IOR(DIAG_MAGIC_STR, 0x78, size_t)
23+
24+
#endif /* __S390_UAPI_ASM_DIAG_H */

arch/s390/kernel/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ obj-y += runtime_instr.o cache.o fpu.o dumpstack.o guarded_storage.o sthyi.o
4242
obj-y += entry.o reipl.o kdebugfs.o alternative.o
4343
obj-y += nospec-branch.o ipl_vmparm.o machine_kexec_reloc.o unwind_bc.o
4444
obj-y += smp.o text_amode31.o stacktrace.o abs_lowcore.o facility.o wti.o uv.o
45+
obj-y += diag/
4546

4647
extra-y += head64.o vmlinux.lds
4748

arch/s390/kernel/diag.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ static const struct diag_desc diag_map[NR_DIAG_STAT] = {
5252
[DIAG_STAT_X308] = { .code = 0x308, .name = "List-Directed IPL" },
5353
[DIAG_STAT_X318] = { .code = 0x318, .name = "CP Name and Version Codes" },
5454
[DIAG_STAT_X320] = { .code = 0x320, .name = "Certificate Store" },
55+
[DIAG_STAT_X324] = { .code = 0x324, .name = "Power Information Block" },
5556
[DIAG_STAT_X49C] = { .code = 0x49c, .name = "Warning-Track Interruption" },
5657
[DIAG_STAT_X500] = { .code = 0x500, .name = "Virtio Service" },
5758
};

arch/s390/kernel/diag/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
obj-y := diag_misc.o
1+
obj-y := diag_misc.o diag324.o

arch/s390/kernel/diag/diag324.c

Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Request power readings for resources in a computing environment via
4+
* diag 0x324. diag 0x324 stores the power readings in the power information
5+
* block (pib).
6+
*
7+
* Copyright IBM Corp. 2024
8+
*/
9+
10+
#define pr_fmt(fmt) "diag324: " fmt
11+
#include <linux/fs.h>
12+
#include <linux/gfp.h>
13+
#include <linux/ioctl.h>
14+
#include <linux/jiffies.h>
15+
#include <linux/kernel.h>
16+
#include <linux/ktime.h>
17+
#include <linux/string.h>
18+
#include <linux/slab.h>
19+
#include <linux/timer.h>
20+
#include <linux/types.h>
21+
#include <linux/uaccess.h>
22+
#include <linux/vmalloc.h>
23+
24+
#include <asm/diag.h>
25+
#include <asm/sclp.h>
26+
#include <asm/timex.h>
27+
#include <uapi/asm/diag.h>
28+
#include "diag_ioctl.h"
29+
30+
enum subcode {
31+
DIAG324_SUBC_0 = 0,
32+
DIAG324_SUBC_1 = 1,
33+
DIAG324_SUBC_2 = 2,
34+
};
35+
36+
enum retcode {
37+
DIAG324_RET_SUCCESS = 0x0001,
38+
DIAG324_RET_SUBC_NOTAVAIL = 0x0103,
39+
DIAG324_RET_INSUFFICIENT_SIZE = 0x0104,
40+
DIAG324_RET_READING_UNAVAILABLE = 0x0105,
41+
};
42+
43+
union diag324_response {
44+
u64 response;
45+
struct {
46+
u64 installed : 32;
47+
u64 : 16;
48+
u64 rc : 16;
49+
} sc0;
50+
struct {
51+
u64 format : 16;
52+
u64 : 16;
53+
u64 pib_len : 16;
54+
u64 rc : 16;
55+
} sc1;
56+
struct {
57+
u64 : 48;
58+
u64 rc : 16;
59+
} sc2;
60+
};
61+
62+
union diag324_request {
63+
u64 request;
64+
struct {
65+
u64 : 32;
66+
u64 allocated : 16;
67+
u64 : 12;
68+
u64 sc : 4;
69+
} sc2;
70+
};
71+
72+
struct pib {
73+
u32 : 8;
74+
u32 num : 8;
75+
u32 len : 16;
76+
u32 : 24;
77+
u32 hlen : 8;
78+
u64 : 64;
79+
u64 intv;
80+
u8 r[];
81+
} __packed;
82+
83+
struct pibdata {
84+
struct pib *pib;
85+
ktime_t expire;
86+
u64 sequence;
87+
size_t len;
88+
int rc;
89+
};
90+
91+
static DEFINE_MUTEX(pibmutex);
92+
static struct pibdata pibdata;
93+
94+
#define PIBWORK_DELAY (5 * NSEC_PER_SEC)
95+
96+
static void pibwork_handler(struct work_struct *work);
97+
static DECLARE_DELAYED_WORK(pibwork, pibwork_handler);
98+
99+
static unsigned long diag324(unsigned long subcode, void *addr)
100+
{
101+
union register_pair rp = { .even = (unsigned long)addr };
102+
103+
diag_stat_inc(DIAG_STAT_X324);
104+
asm volatile("diag %[rp],%[subcode],0x324\n"
105+
: [rp] "+d" (rp.pair)
106+
: [subcode] "d" (subcode)
107+
: "memory");
108+
return rp.odd;
109+
}
110+
111+
static void pibwork_handler(struct work_struct *work)
112+
{
113+
struct pibdata *data = &pibdata;
114+
ktime_t timedout;
115+
116+
mutex_lock(&pibmutex);
117+
timedout = ktime_add_ns(data->expire, PIBWORK_DELAY);
118+
if (ktime_before(ktime_get(), timedout)) {
119+
mod_delayed_work(system_wq, &pibwork, nsecs_to_jiffies(PIBWORK_DELAY));
120+
goto out;
121+
}
122+
vfree(data->pib);
123+
data->pib = NULL;
124+
out:
125+
mutex_unlock(&pibmutex);
126+
}
127+
128+
static void pib_update(struct pibdata *data)
129+
{
130+
union diag324_request req = { .sc2.sc = DIAG324_SUBC_2, .sc2.allocated = data->len };
131+
union diag324_response res;
132+
int rc;
133+
134+
memset(data->pib, 0, data->len);
135+
res.response = diag324(req.request, data->pib);
136+
switch (res.sc2.rc) {
137+
case DIAG324_RET_SUCCESS:
138+
rc = 0;
139+
break;
140+
case DIAG324_RET_SUBC_NOTAVAIL:
141+
rc = -ENOENT;
142+
break;
143+
case DIAG324_RET_INSUFFICIENT_SIZE:
144+
rc = -EMSGSIZE;
145+
break;
146+
case DIAG324_RET_READING_UNAVAILABLE:
147+
rc = -EBUSY;
148+
break;
149+
default:
150+
rc = -EINVAL;
151+
}
152+
data->rc = rc;
153+
}
154+
155+
long diag324_pibbuf(unsigned long arg)
156+
{
157+
struct diag324_pib __user *udata = (struct diag324_pib __user *)arg;
158+
struct pibdata *data = &pibdata;
159+
static bool first = true;
160+
u64 address;
161+
int rc;
162+
163+
if (!data->len)
164+
return -EOPNOTSUPP;
165+
if (get_user(address, &udata->address))
166+
return -EFAULT;
167+
mutex_lock(&pibmutex);
168+
rc = -ENOMEM;
169+
if (!data->pib)
170+
data->pib = vmalloc(data->len);
171+
if (!data->pib)
172+
goto out;
173+
if (first || ktime_after(ktime_get(), data->expire)) {
174+
pib_update(data);
175+
data->sequence++;
176+
data->expire = ktime_add_ns(ktime_get(), tod_to_ns(data->pib->intv));
177+
mod_delayed_work(system_wq, &pibwork, nsecs_to_jiffies(PIBWORK_DELAY));
178+
first = false;
179+
}
180+
rc = data->rc;
181+
if (rc != 0 && rc != -EBUSY)
182+
goto out;
183+
rc = copy_to_user((void __user *)address, data->pib, data->pib->len);
184+
rc |= put_user(data->sequence, &udata->sequence);
185+
if (rc)
186+
rc = -EFAULT;
187+
out:
188+
mutex_unlock(&pibmutex);
189+
return rc;
190+
}
191+
192+
long diag324_piblen(unsigned long arg)
193+
{
194+
struct pibdata *data = &pibdata;
195+
196+
if (!data->len)
197+
return -EOPNOTSUPP;
198+
if (put_user(data->len, (size_t __user *)arg))
199+
return -EFAULT;
200+
return 0;
201+
}
202+
203+
static int __init diag324_init(void)
204+
{
205+
union diag324_response res;
206+
unsigned long installed;
207+
208+
if (!sclp.has_diag324)
209+
return -EOPNOTSUPP;
210+
res.response = diag324(DIAG324_SUBC_0, NULL);
211+
if (res.sc0.rc != DIAG324_RET_SUCCESS)
212+
return -EOPNOTSUPP;
213+
installed = res.response;
214+
if (!test_bit_inv(DIAG324_SUBC_1, &installed))
215+
return -EOPNOTSUPP;
216+
if (!test_bit_inv(DIAG324_SUBC_2, &installed))
217+
return -EOPNOTSUPP;
218+
res.response = diag324(DIAG324_SUBC_1, NULL);
219+
if (res.sc1.rc != DIAG324_RET_SUCCESS)
220+
return -EOPNOTSUPP;
221+
pibdata.len = res.sc1.pib_len;
222+
return 0;
223+
}
224+
device_initcall(diag324_init);

arch/s390/kernel/diag/diag_ioctl.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
#ifndef _DIAG_IOCTL_H
3+
#define _DIAG_IOCTL_H
4+
5+
#include <linux/types.h>
6+
7+
long diag324_pibbuf(unsigned long arg);
8+
long diag324_piblen(unsigned long arg);
9+
10+
#endif /* _DIAG_IOCTL_H */

arch/s390/kernel/diag/diag_misc.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,20 @@
1212
#include <linux/miscdevice.h>
1313
#include <linux/types.h>
1414

15+
#include <uapi/asm/diag.h>
16+
#include "diag_ioctl.h"
17+
1518
static long diag_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
1619
{
1720
long rc;
1821

1922
switch (cmd) {
23+
case DIAG324_GET_PIBLEN:
24+
rc = diag324_piblen(arg);
25+
break;
26+
case DIAG324_GET_PIBBUF:
27+
rc = diag324_pibbuf(arg);
28+
break;
2029
default:
2130
rc = -ENOIOCTLCMD;
2231
break;

drivers/s390/char/sclp.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,9 @@ struct read_info_sccb {
188188
u8 byte_134; /* 134 */
189189
u8 cpudirq; /* 135 */
190190
u16 cbl; /* 136-137 */
191-
u8 _pad_138[EXT_SCCB_READ_SCP - 138];
191+
u8 byte_138; /* 138 */
192+
u8 byte_139; /* 139 */
193+
u8 _pad_140[EXT_SCCB_READ_SCP - 140];
192194
} __packed __aligned(PAGE_SIZE);
193195

194196
struct read_storage_sccb {

0 commit comments

Comments
 (0)