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 sclp_ocf_cpc_name_copy(sctns
->mac
.infmname
);
187 if (*(u64
*)sctns
->mac
.infmname
!= 0)
188 sctns
->mac
.infmval1
|= MAC_NAME_VLD
;
190 if (stsi(sysinfo
, 1, 1, 1))
193 memcpy(sctns
->mac
.infmtype
, sysinfo
->type
, sizeof(sctns
->mac
.infmtype
));
194 memcpy(sctns
->mac
.infmmanu
, sysinfo
->manufacturer
, sizeof(sctns
->mac
.infmmanu
));
195 memcpy(sctns
->mac
.infmpman
, sysinfo
->plant
, sizeof(sctns
->mac
.infmpman
));
196 memcpy(sctns
->mac
.infmseq
, sysinfo
->sequence
, sizeof(sctns
->mac
.infmseq
));
198 sctns
->mac
.infmval1
|= MAC_ID_VLD
;
201 static void fill_stsi_par(struct sthyi_sctns
*sctns
,
202 struct sysinfo_2_2_2
*sysinfo
)
204 if (stsi(sysinfo
, 2, 2, 2))
207 sctns
->par
.infppnum
= sysinfo
->lpar_number
;
208 memcpy(sctns
->par
.infppnam
, sysinfo
->name
, sizeof(sctns
->par
.infppnam
));
210 sctns
->par
.infpval1
|= PAR_ID_VLD
;
213 static void fill_stsi(struct sthyi_sctns
*sctns
)
217 /* Errors are handled through the validity bits in the response. */
218 sysinfo
= (void *)__get_free_page(GFP_KERNEL
);
222 fill_stsi_mac(sctns
, sysinfo
);
223 fill_stsi_par(sctns
, sysinfo
);
225 free_pages((unsigned long)sysinfo
, 0);
228 static void fill_diag_mac(struct sthyi_sctns
*sctns
,
229 struct diag204_x_phys_block
*block
,
234 for (i
= 0; i
< block
->hdr
.cpus
; i
++) {
235 switch (cpu_id(block
->cpus
[i
].ctidx
, diag224_buf
)) {
237 if (block
->cpus
[i
].weight
== DED_WEIGHT
)
238 sctns
->mac
.infmdcps
++;
240 sctns
->mac
.infmscps
++;
243 if (block
->cpus
[i
].weight
== DED_WEIGHT
)
244 sctns
->mac
.infmdifl
++;
246 sctns
->mac
.infmsifl
++;
250 sctns
->mac
.infmval1
|= MAC_CNT_VLD
;
253 /* Returns a pointer to the the next partition block. */
254 static struct diag204_x_part_block
*lpar_cpu_inf(struct lpar_cpu_inf
*part_inf
,
257 struct diag204_x_part_block
*block
)
259 int i
, capped
= 0, weight_cp
= 0, weight_ifl
= 0;
260 struct cpu_inf
*cpu_inf
;
262 for (i
= 0; i
< block
->hdr
.rcpus
; i
++) {
263 if (!(block
->cpus
[i
].cflag
& DIAG204_CPU_ONLINE
))
266 switch (cpu_id(block
->cpus
[i
].ctidx
, diag224_buf
)) {
268 cpu_inf
= &part_inf
->cp
;
269 if (block
->cpus
[i
].cur_weight
< DED_WEIGHT
)
270 weight_cp
|= block
->cpus
[i
].cur_weight
;
273 cpu_inf
= &part_inf
->ifl
;
274 if (block
->cpus
[i
].cur_weight
< DED_WEIGHT
)
275 weight_ifl
|= block
->cpus
[i
].cur_weight
;
284 capped
|= block
->cpus
[i
].cflag
& DIAG204_CPU_CAPPED
;
285 cpu_inf
->lpar_cap
|= block
->cpus
[i
].cpu_type_cap
;
286 cpu_inf
->lpar_grp_cap
|= block
->cpus
[i
].group_cpu_type_cap
;
288 if (block
->cpus
[i
].weight
== DED_WEIGHT
)
289 cpu_inf
->cpu_num_ded
+= 1;
291 cpu_inf
->cpu_num_shd
+= 1;
294 if (this_lpar
&& capped
) {
295 part_inf
->cp
.lpar_weight
= weight_cp
;
296 part_inf
->ifl
.lpar_weight
= weight_ifl
;
298 part_inf
->cp
.all_weight
+= weight_cp
;
299 part_inf
->ifl
.all_weight
+= weight_ifl
;
300 return (struct diag204_x_part_block
*)&block
->cpus
[i
];
303 static void fill_diag(struct sthyi_sctns
*sctns
)
308 void *diag224_buf
= NULL
;
309 struct diag204_x_info_blk_hdr
*ti_hdr
;
310 struct diag204_x_part_block
*part_block
;
311 struct diag204_x_phys_block
*phys_block
;
312 struct lpar_cpu_inf lpar_inf
= {};
314 /* Errors are handled through the validity bits in the response. */
315 pages
= diag204((unsigned long)DIAG204_SUBC_RSI
|
316 (unsigned long)DIAG204_INFO_EXT
, 0, NULL
);
320 diag204_buf
= vmalloc(array_size(pages
, PAGE_SIZE
));
324 r
= diag204((unsigned long)DIAG204_SUBC_STIB7
|
325 (unsigned long)DIAG204_INFO_EXT
, pages
, diag204_buf
);
329 diag224_buf
= (void *)__get_free_page(GFP_KERNEL
| GFP_DMA
);
330 if (!diag224_buf
|| diag224(diag224_buf
))
333 ti_hdr
= diag204_buf
;
334 part_block
= diag204_buf
+ sizeof(*ti_hdr
);
336 for (i
= 0; i
< ti_hdr
->npar
; i
++) {
338 * For the calling lpar we also need to get the cpu
339 * caps and weights. The time information block header
340 * specifies the offset to the partition block of the
341 * caller lpar, so we know when we process its data.
343 this_lpar
= (void *)part_block
- diag204_buf
== ti_hdr
->this_part
;
344 part_block
= lpar_cpu_inf(&lpar_inf
, this_lpar
, diag224_buf
,
348 phys_block
= (struct diag204_x_phys_block
*)part_block
;
349 part_block
= diag204_buf
+ ti_hdr
->this_part
;
350 if (part_block
->hdr
.mtid
)
351 sctns
->par
.infpflg1
= PAR_MT_EN
;
353 sctns
->par
.infpval1
|= PAR_GRP_VLD
;
354 sctns
->par
.infplgcp
= scale_cap(lpar_inf
.cp
.lpar_grp_cap
);
355 sctns
->par
.infplgif
= scale_cap(lpar_inf
.ifl
.lpar_grp_cap
);
356 memcpy(sctns
->par
.infplgnm
, part_block
->hdr
.hardware_group_name
,
357 sizeof(sctns
->par
.infplgnm
));
359 sctns
->par
.infpscps
= lpar_inf
.cp
.cpu_num_shd
;
360 sctns
->par
.infpdcps
= lpar_inf
.cp
.cpu_num_ded
;
361 sctns
->par
.infpsifl
= lpar_inf
.ifl
.cpu_num_shd
;
362 sctns
->par
.infpdifl
= lpar_inf
.ifl
.cpu_num_ded
;
363 sctns
->par
.infpval1
|= PAR_PCNT_VLD
;
365 sctns
->par
.infpabcp
= scale_cap(lpar_inf
.cp
.lpar_cap
);
366 sctns
->par
.infpabif
= scale_cap(lpar_inf
.ifl
.lpar_cap
);
367 sctns
->par
.infpval1
|= PAR_ABS_VLD
;
370 * Everything below needs global performance data to be
373 if (!(ti_hdr
->flags
& DIAG204_LPAR_PHYS_FLG
)) {
374 sctns
->hdr
.infhflg1
|= HDR_PERF_UNAV
;
378 fill_diag_mac(sctns
, phys_block
, diag224_buf
);
380 if (lpar_inf
.cp
.lpar_weight
) {
381 sctns
->par
.infpwbcp
= sctns
->mac
.infmscps
* 0x10000 *
382 lpar_inf
.cp
.lpar_weight
/ lpar_inf
.cp
.all_weight
;
385 if (lpar_inf
.ifl
.lpar_weight
) {
386 sctns
->par
.infpwbif
= sctns
->mac
.infmsifl
* 0x10000 *
387 lpar_inf
.ifl
.lpar_weight
/ lpar_inf
.ifl
.all_weight
;
389 sctns
->par
.infpval1
|= PAR_WGHT_VLD
;
392 free_page((unsigned long)diag224_buf
);
396 static int sthyi(u64 vaddr
, u64
*rc
)
398 register u64 code
asm("0") = 0;
399 register u64 addr
asm("2") = vaddr
;
400 register u64 rcode
asm("3");
404 ".insn rre,0xB2560000,%[code],%[addr]\n"
407 : [cc
] "=d" (cc
), "=d" (rcode
)
408 : [code
] "d" (code
), [addr
] "a" (addr
)
414 static int fill_dst(void *dst
, u64
*rc
)
416 struct sthyi_sctns
*sctns
= (struct sthyi_sctns
*)dst
;
419 * If the facility is on, we don't want to emulate the instruction.
420 * We ask the hypervisor to provide the data.
422 if (test_facility(74))
423 return sthyi((u64
)dst
, rc
);
432 static int sthyi_init_cache(void)
434 if (sthyi_cache
.info
)
436 sthyi_cache
.info
= (void *)get_zeroed_page(GFP_KERNEL
);
437 if (!sthyi_cache
.info
)
439 sthyi_cache
.end
= jiffies
- 1; /* expired */
443 static int sthyi_update_cache(u64
*rc
)
447 memset(sthyi_cache
.info
, 0, PAGE_SIZE
);
448 r
= fill_dst(sthyi_cache
.info
, rc
);
451 sthyi_cache
.end
= jiffies
+ CACHE_VALID_JIFFIES
;
456 * sthyi_fill - Fill page with data returned by the STHYI instruction
458 * @dst: Pointer to zeroed page
459 * @rc: Pointer for storing the return code of the instruction
461 * Fills the destination with system information returned by the STHYI
462 * instruction. The data is generated by emulation or execution of STHYI,
463 * if available. The return value is the condition code that would be
464 * returned, the rc parameter is the return code which is passed in
467 int sthyi_fill(void *dst
, u64
*rc
)
471 mutex_lock(&sthyi_mutex
);
472 r
= sthyi_init_cache();
476 if (time_is_before_jiffies(sthyi_cache
.end
)) {
478 r
= sthyi_update_cache(rc
);
483 memcpy(dst
, sthyi_cache
.info
, PAGE_SIZE
);
485 mutex_unlock(&sthyi_mutex
);
488 EXPORT_SYMBOL_GPL(sthyi_fill
);
490 SYSCALL_DEFINE4(s390_sthyi
, unsigned long, function_code
, void __user
*, buffer
,
491 u64 __user
*, return_code
, unsigned long, flags
)
499 if (function_code
!= STHYI_FC_CP_IFL_CAP
)
501 info
= (void *)get_zeroed_page(GFP_KERNEL
);
504 r
= sthyi_fill(info
, &sthyi_rc
);
507 if (return_code
&& put_user(sthyi_rc
, return_code
)) {
511 if (copy_to_user(buffer
, info
, PAGE_SIZE
))
514 free_page((unsigned long)info
);