1 // SPDX-License-Identifier: GPL-2.0
3 * store hypervisor information instruction emulation functions.
5 * Copyright IBM Corp. 2016
6 * Author(s): Janosch Frank <frankja@linux.vnet.ibm.com>
8 #include <linux/errno.h>
9 #include <linux/pagemap.h>
10 #include <linux/vmalloc.h>
11 #include <linux/syscalls.h>
12 #include <linux/mutex.h>
13 #include <asm/asm-offsets.h>
16 #include <asm/sysinfo.h>
17 #include <asm/ebcdic.h>
18 #include <asm/facility.h>
19 #include <asm/sthyi.h>
22 #define DED_WEIGHT 0xffff
24 * CP and IFL as EBCDIC strings, SP/0x40 determines the end of string
25 * as they are justified with spaces.
27 #define CP 0xc3d7404040404040UL
28 #define IFL 0xc9c6d34040404040UL
32 HDR_STACK_INCM
= 0x20,
57 u8 infhflg2
; /* reserved */
58 u8 infhval1
; /* reserved */
59 u8 infhval2
; /* reserved */
84 u8 infmflg1
; /* reserved */
85 u8 infmflg2
; /* reserved */
87 u8 infmval2
; /* reserved */
102 u8 infpflg2
; /* reserved */
104 u8 infpval2
; /* reserved */
136 struct lpar_cpu_inf
{
142 * STHYI requires extensive locking in the higher hypervisors
143 * and is very computational/memory expensive. Therefore we
144 * cache the retrieved data whose valid period is 1s.
146 #define CACHE_VALID_JIFFIES HZ
153 static DEFINE_MUTEX(sthyi_mutex
);
154 static struct sthyi_info sthyi_cache
;
156 static inline u64
cpu_id(u8 ctidx
, void *diag224_buf
)
158 return *((u64
*)(diag224_buf
+ (ctidx
+ 1) * DIAG204_CPU_NAME_LEN
));
162 * Scales the cpu capping from the lpar range to the one expected in
165 * diag204 reports a cap in hundredths of processor units.
166 * z/VM's range for one core is 0 - 0x10000.
168 static u32
scale_cap(u32 in
)
170 return (0x10000 * in
) / 100;
173 static void fill_hdr(struct sthyi_sctns
*sctns
)
175 sctns
->hdr
.infhdln
= sizeof(sctns
->hdr
);
176 sctns
->hdr
.infmoff
= sizeof(sctns
->hdr
);
177 sctns
->hdr
.infmlen
= sizeof(sctns
->mac
);
178 sctns
->hdr
.infplen
= sizeof(sctns
->par
);
179 sctns
->hdr
.infpoff
= sctns
->hdr
.infhdln
+ sctns
->hdr
.infmlen
;
180 sctns
->hdr
.infhtotl
= sctns
->hdr
.infpoff
+ sctns
->hdr
.infplen
;
183 static void fill_stsi_mac(struct sthyi_sctns
*sctns
,
184 struct sysinfo_1_1_1
*sysinfo
)
186 if (stsi(sysinfo
, 1, 1, 1))
189 sclp_ocf_cpc_name_copy(sctns
->mac
.infmname
);
191 memcpy(sctns
->mac
.infmtype
, sysinfo
->type
, sizeof(sctns
->mac
.infmtype
));
192 memcpy(sctns
->mac
.infmmanu
, sysinfo
->manufacturer
, sizeof(sctns
->mac
.infmmanu
));
193 memcpy(sctns
->mac
.infmpman
, sysinfo
->plant
, sizeof(sctns
->mac
.infmpman
));
194 memcpy(sctns
->mac
.infmseq
, sysinfo
->sequence
, sizeof(sctns
->mac
.infmseq
));
196 sctns
->mac
.infmval1
|= MAC_ID_VLD
| MAC_NAME_VLD
;
199 static void fill_stsi_par(struct sthyi_sctns
*sctns
,
200 struct sysinfo_2_2_2
*sysinfo
)
202 if (stsi(sysinfo
, 2, 2, 2))
205 sctns
->par
.infppnum
= sysinfo
->lpar_number
;
206 memcpy(sctns
->par
.infppnam
, sysinfo
->name
, sizeof(sctns
->par
.infppnam
));
208 sctns
->par
.infpval1
|= PAR_ID_VLD
;
211 static void fill_stsi(struct sthyi_sctns
*sctns
)
215 /* Errors are handled through the validity bits in the response. */
216 sysinfo
= (void *)__get_free_page(GFP_KERNEL
);
220 fill_stsi_mac(sctns
, sysinfo
);
221 fill_stsi_par(sctns
, sysinfo
);
223 free_pages((unsigned long)sysinfo
, 0);
226 static void fill_diag_mac(struct sthyi_sctns
*sctns
,
227 struct diag204_x_phys_block
*block
,
232 for (i
= 0; i
< block
->hdr
.cpus
; i
++) {
233 switch (cpu_id(block
->cpus
[i
].ctidx
, diag224_buf
)) {
235 if (block
->cpus
[i
].weight
== DED_WEIGHT
)
236 sctns
->mac
.infmdcps
++;
238 sctns
->mac
.infmscps
++;
241 if (block
->cpus
[i
].weight
== DED_WEIGHT
)
242 sctns
->mac
.infmdifl
++;
244 sctns
->mac
.infmsifl
++;
248 sctns
->mac
.infmval1
|= MAC_CNT_VLD
;
251 /* Returns a pointer to the the next partition block. */
252 static struct diag204_x_part_block
*lpar_cpu_inf(struct lpar_cpu_inf
*part_inf
,
255 struct diag204_x_part_block
*block
)
257 int i
, capped
= 0, weight_cp
= 0, weight_ifl
= 0;
258 struct cpu_inf
*cpu_inf
;
260 for (i
= 0; i
< block
->hdr
.rcpus
; i
++) {
261 if (!(block
->cpus
[i
].cflag
& DIAG204_CPU_ONLINE
))
264 switch (cpu_id(block
->cpus
[i
].ctidx
, diag224_buf
)) {
266 cpu_inf
= &part_inf
->cp
;
267 if (block
->cpus
[i
].cur_weight
< DED_WEIGHT
)
268 weight_cp
|= block
->cpus
[i
].cur_weight
;
271 cpu_inf
= &part_inf
->ifl
;
272 if (block
->cpus
[i
].cur_weight
< DED_WEIGHT
)
273 weight_ifl
|= block
->cpus
[i
].cur_weight
;
282 capped
|= block
->cpus
[i
].cflag
& DIAG204_CPU_CAPPED
;
283 cpu_inf
->lpar_cap
|= block
->cpus
[i
].cpu_type_cap
;
284 cpu_inf
->lpar_grp_cap
|= block
->cpus
[i
].group_cpu_type_cap
;
286 if (block
->cpus
[i
].weight
== DED_WEIGHT
)
287 cpu_inf
->cpu_num_ded
+= 1;
289 cpu_inf
->cpu_num_shd
+= 1;
292 if (this_lpar
&& capped
) {
293 part_inf
->cp
.lpar_weight
= weight_cp
;
294 part_inf
->ifl
.lpar_weight
= weight_ifl
;
296 part_inf
->cp
.all_weight
+= weight_cp
;
297 part_inf
->ifl
.all_weight
+= weight_ifl
;
298 return (struct diag204_x_part_block
*)&block
->cpus
[i
];
301 static void fill_diag(struct sthyi_sctns
*sctns
)
306 void *diag224_buf
= NULL
;
307 struct diag204_x_info_blk_hdr
*ti_hdr
;
308 struct diag204_x_part_block
*part_block
;
309 struct diag204_x_phys_block
*phys_block
;
310 struct lpar_cpu_inf lpar_inf
= {};
312 /* Errors are handled through the validity bits in the response. */
313 pages
= diag204((unsigned long)DIAG204_SUBC_RSI
|
314 (unsigned long)DIAG204_INFO_EXT
, 0, NULL
);
318 diag204_buf
= vmalloc(PAGE_SIZE
* pages
);
322 r
= diag204((unsigned long)DIAG204_SUBC_STIB7
|
323 (unsigned long)DIAG204_INFO_EXT
, pages
, diag204_buf
);
327 diag224_buf
= (void *)__get_free_page(GFP_KERNEL
| GFP_DMA
);
328 if (!diag224_buf
|| diag224(diag224_buf
))
331 ti_hdr
= diag204_buf
;
332 part_block
= diag204_buf
+ sizeof(*ti_hdr
);
334 for (i
= 0; i
< ti_hdr
->npar
; i
++) {
336 * For the calling lpar we also need to get the cpu
337 * caps and weights. The time information block header
338 * specifies the offset to the partition block of the
339 * caller lpar, so we know when we process its data.
341 this_lpar
= (void *)part_block
- diag204_buf
== ti_hdr
->this_part
;
342 part_block
= lpar_cpu_inf(&lpar_inf
, this_lpar
, diag224_buf
,
346 phys_block
= (struct diag204_x_phys_block
*)part_block
;
347 part_block
= diag204_buf
+ ti_hdr
->this_part
;
348 if (part_block
->hdr
.mtid
)
349 sctns
->par
.infpflg1
= PAR_MT_EN
;
351 sctns
->par
.infpval1
|= PAR_GRP_VLD
;
352 sctns
->par
.infplgcp
= scale_cap(lpar_inf
.cp
.lpar_grp_cap
);
353 sctns
->par
.infplgif
= scale_cap(lpar_inf
.ifl
.lpar_grp_cap
);
354 memcpy(sctns
->par
.infplgnm
, part_block
->hdr
.hardware_group_name
,
355 sizeof(sctns
->par
.infplgnm
));
357 sctns
->par
.infpscps
= lpar_inf
.cp
.cpu_num_shd
;
358 sctns
->par
.infpdcps
= lpar_inf
.cp
.cpu_num_ded
;
359 sctns
->par
.infpsifl
= lpar_inf
.ifl
.cpu_num_shd
;
360 sctns
->par
.infpdifl
= lpar_inf
.ifl
.cpu_num_ded
;
361 sctns
->par
.infpval1
|= PAR_PCNT_VLD
;
363 sctns
->par
.infpabcp
= scale_cap(lpar_inf
.cp
.lpar_cap
);
364 sctns
->par
.infpabif
= scale_cap(lpar_inf
.ifl
.lpar_cap
);
365 sctns
->par
.infpval1
|= PAR_ABS_VLD
;
368 * Everything below needs global performance data to be
371 if (!(ti_hdr
->flags
& DIAG204_LPAR_PHYS_FLG
)) {
372 sctns
->hdr
.infhflg1
|= HDR_PERF_UNAV
;
376 fill_diag_mac(sctns
, phys_block
, diag224_buf
);
378 if (lpar_inf
.cp
.lpar_weight
) {
379 sctns
->par
.infpwbcp
= sctns
->mac
.infmscps
* 0x10000 *
380 lpar_inf
.cp
.lpar_weight
/ lpar_inf
.cp
.all_weight
;
383 if (lpar_inf
.ifl
.lpar_weight
) {
384 sctns
->par
.infpwbif
= sctns
->mac
.infmsifl
* 0x10000 *
385 lpar_inf
.ifl
.lpar_weight
/ lpar_inf
.ifl
.all_weight
;
387 sctns
->par
.infpval1
|= PAR_WGHT_VLD
;
390 free_page((unsigned long)diag224_buf
);
394 static int sthyi(u64 vaddr
, u64
*rc
)
396 register u64 code
asm("0") = 0;
397 register u64 addr
asm("2") = vaddr
;
398 register u64 rcode
asm("3");
402 ".insn rre,0xB2560000,%[code],%[addr]\n"
405 : [cc
] "=d" (cc
), "=d" (rcode
)
406 : [code
] "d" (code
), [addr
] "a" (addr
)
412 static int fill_dst(void *dst
, u64
*rc
)
414 struct sthyi_sctns
*sctns
= (struct sthyi_sctns
*)dst
;
417 * If the facility is on, we don't want to emulate the instruction.
418 * We ask the hypervisor to provide the data.
420 if (test_facility(74))
421 return sthyi((u64
)dst
, rc
);
430 static int sthyi_init_cache(void)
432 if (sthyi_cache
.info
)
434 sthyi_cache
.info
= (void *)get_zeroed_page(GFP_KERNEL
);
435 if (!sthyi_cache
.info
)
437 sthyi_cache
.end
= jiffies
- 1; /* expired */
441 static int sthyi_update_cache(u64
*rc
)
445 memset(sthyi_cache
.info
, 0, PAGE_SIZE
);
446 r
= fill_dst(sthyi_cache
.info
, rc
);
449 sthyi_cache
.end
= jiffies
+ CACHE_VALID_JIFFIES
;
454 * sthyi_fill - Fill page with data returned by the STHYI instruction
456 * @dst: Pointer to zeroed page
457 * @rc: Pointer for storing the return code of the instruction
459 * Fills the destination with system information returned by the STHYI
460 * instruction. The data is generated by emulation or execution of STHYI,
461 * if available. The return value is the condition code that would be
462 * returned, the rc parameter is the return code which is passed in
465 int sthyi_fill(void *dst
, u64
*rc
)
469 mutex_lock(&sthyi_mutex
);
470 r
= sthyi_init_cache();
474 if (time_is_before_jiffies(sthyi_cache
.end
)) {
476 r
= sthyi_update_cache(rc
);
481 memcpy(dst
, sthyi_cache
.info
, PAGE_SIZE
);
483 mutex_unlock(&sthyi_mutex
);
486 EXPORT_SYMBOL_GPL(sthyi_fill
);
488 SYSCALL_DEFINE4(s390_sthyi
, unsigned long, function_code
, void __user
*, buffer
,
489 u64 __user
*, return_code
, unsigned long, flags
)
497 if (function_code
!= STHYI_FC_CP_IFL_CAP
)
499 info
= (void *)get_zeroed_page(GFP_KERNEL
);
502 r
= sthyi_fill(info
, &sthyi_rc
);
505 if (return_code
&& put_user(sthyi_rc
, return_code
)) {
509 if (copy_to_user(buffer
, info
, PAGE_SIZE
))
512 free_page((unsigned long)info
);