Skip to content

Commit 839e349

Browse files
committed
Merge: [s390] LPAR level power consumption reporting - kernel part
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/6672 JIRA: https://issues.redhat.com/browse/RHEL-72676 Conflicts: Minor merge conflict - no functional change Commits: ``` 388cf16 90e6f19 2478d43 ``` Signed-off-by: Mete Durlu <[email protected]> Approved-by: Steve Best <[email protected]> Approved-by: Tony Camuso <[email protected]> Approved-by: CKI KWF Bot <[email protected]> Merged-by: Augusto Caringi <[email protected]>
2 parents 44633a5 + 5516696 commit 839e349

File tree

11 files changed

+324
-3
lines changed

11 files changed

+324
-3
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: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,13 @@ CFLAGS_unwind_bc.o += -fno-optimize-sibling-calls
3636

3737
obj-y := traps.o time.o process.o earlypgm.o early.o setup.o idle.o vtime.o
3838
obj-y += processor.o syscall.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o
39-
obj-y += debug.o irq.o ipl.o dis.o diag.o vdso.o cpufeature.o
39+
obj-y += debug.o irq.o ipl.o dis.o vdso.o cpufeature.o
4040
obj-y += sysinfo.o lgr.o os_info.o ctlreg.o
4141
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/Makefile

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

arch/s390/kernel/diag.c renamed to arch/s390/kernel/diag/diag.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
#include <asm/diag.h>
1717
#include <asm/trace/diag.h>
1818
#include <asm/sections.h>
19-
#include "entry.h"
19+
#include "../entry.h"
2020

2121
struct diag_stat {
2222
unsigned int counter[NR_DIAG_STAT];
@@ -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/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: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Provide diagnose information via misc device /dev/diag.
4+
*
5+
* Copyright IBM Corp. 2024
6+
*/
7+
8+
#include <linux/fs.h>
9+
#include <linux/init.h>
10+
#include <linux/ioctl.h>
11+
#include <linux/kernel.h>
12+
#include <linux/miscdevice.h>
13+
#include <linux/types.h>
14+
15+
#include <uapi/asm/diag.h>
16+
#include "diag_ioctl.h"
17+
18+
static long diag_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
19+
{
20+
long rc;
21+
22+
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;
29+
default:
30+
rc = -ENOIOCTLCMD;
31+
break;
32+
}
33+
return rc;
34+
}
35+
36+
static const struct file_operations fops = {
37+
.owner = THIS_MODULE,
38+
.open = nonseekable_open,
39+
.unlocked_ioctl = diag_ioctl,
40+
};
41+
42+
static struct miscdevice diagdev = {
43+
.name = "diag",
44+
.minor = MISC_DYNAMIC_MINOR,
45+
.fops = &fops,
46+
.mode = 0444,
47+
};
48+
49+
static int diag_init(void)
50+
{
51+
return misc_register(&diagdev);
52+
}
53+
54+
device_initcall(diag_init);

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 {

drivers/s390/char/sclp_early.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ static void __init sclp_early_facilities_detect(void)
6363
sclp.has_sipl = !!(sccb->cbl & 0x4000);
6464
sclp.has_sipl_eckd = !!(sccb->cbl & 0x2000);
6565
}
66+
if (sccb->cpuoff > 139)
67+
sclp.has_diag324 = !!(sccb->byte_139 & 0x80);
6668
sclp.rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2;
6769
sclp.rzm = sccb->rnsize ? sccb->rnsize : sccb->rnsize2;
6870
sclp.rzm <<= 20;

0 commit comments

Comments
 (0)