1 // SPDX-License-Identifier: GPL-2.0
5 * Copyright IBM Corp. 2013
8 #define KMSG_COMPONENT "sclp_early"
9 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
11 #include <linux/errno.h>
12 #include <linux/memblock.h>
13 #include <asm/ctl_reg.h>
16 #include <asm/setup.h>
17 #include <asm/facility.h>
18 #include "sclp_sdias.h"
21 static struct sclp_ipl_info sclp_ipl_info
;
23 struct sclp_info sclp
;
26 static void __init
sclp_early_facilities_detect(void)
28 struct sclp_core_entry
*cpue
;
29 struct read_info_sccb
*sccb
;
30 u16 boot_cpu_address
, cpu
;
32 sccb
= sclp_early_get_info();
36 sclp
.facilities
= sccb
->facilities
;
37 sclp
.has_sprp
= !!(sccb
->fac84
& 0x02);
38 sclp
.has_core_type
= !!(sccb
->fac84
& 0x01);
39 sclp
.has_gsls
= !!(sccb
->fac85
& 0x80);
40 sclp
.has_64bscao
= !!(sccb
->fac116
& 0x80);
41 sclp
.has_cmma
= !!(sccb
->fac116
& 0x40);
42 sclp
.has_esca
= !!(sccb
->fac116
& 0x08);
43 sclp
.has_pfmfi
= !!(sccb
->fac117
& 0x40);
44 sclp
.has_ibs
= !!(sccb
->fac117
& 0x20);
45 sclp
.has_gisaf
= !!(sccb
->fac118
& 0x08);
46 sclp
.has_hvs
= !!(sccb
->fac119
& 0x80);
47 sclp
.has_kss
= !!(sccb
->fac98
& 0x01);
48 sclp
.has_sipl
= !!(sccb
->cbl
& 0x4000);
49 if (sccb
->fac85
& 0x02)
50 S390_lowcore
.machine_flags
|= MACHINE_FLAG_ESOP
;
51 if (sccb
->fac91
& 0x40)
52 S390_lowcore
.machine_flags
|= MACHINE_FLAG_TLB_GUEST
;
53 if (sccb
->cpuoff
> 134)
54 sclp
.has_diag318
= !!(sccb
->byte_134
& 0x80);
55 sclp
.rnmax
= sccb
->rnmax
? sccb
->rnmax
: sccb
->rnmax2
;
56 sclp
.rzm
= sccb
->rnsize
? sccb
->rnsize
: sccb
->rnsize2
;
60 if (sccb
->hamaxpow
&& sccb
->hamaxpow
< 64)
61 sclp
.hamax
= (1UL << sccb
->hamaxpow
) - 1;
69 sclp
.max_cores
= sccb
->ncpurl
;
71 sclp
.max_cores
= sccb
->hcpua
+ 1;
74 boot_cpu_address
= stap();
75 cpue
= (void *)sccb
+ sccb
->cpuoff
;
76 for (cpu
= 0; cpu
< sccb
->ncpurl
; cpue
++, cpu
++) {
77 if (boot_cpu_address
!= cpue
->core_id
)
79 sclp
.has_siif
= cpue
->siif
;
80 sclp
.has_sigpif
= cpue
->sigpif
;
81 sclp
.has_sief2
= cpue
->sief2
;
82 sclp
.has_gpere
= cpue
->gpere
;
83 sclp
.has_ib
= cpue
->ib
;
84 sclp
.has_cei
= cpue
->cei
;
85 sclp
.has_skey
= cpue
->skey
;
89 /* Save IPL information */
90 sclp_ipl_info
.is_valid
= 1;
91 if (sccb
->fac91
& 0x2)
92 sclp_ipl_info
.has_dump
= 1;
93 memcpy(&sclp_ipl_info
.loadparm
, &sccb
->loadparm
, LOADPARM_LEN
);
96 sclp
.hsa_size
= (sccb
->hsa_size
- 1) * PAGE_SIZE
;
97 sclp
.mtid
= (sccb
->fac42
& 0x80) ? (sccb
->fac42
& 31) : 0;
98 sclp
.mtid_cp
= (sccb
->fac42
& 0x80) ? (sccb
->fac43
& 31) : 0;
99 sclp
.mtid_prev
= (sccb
->fac42
& 0x80) ? (sccb
->fac66
& 31) : 0;
101 sclp
.hmfai
= sccb
->hmfai
;
102 sclp
.has_dirq
= !!(sccb
->cpudirq
& 0x80);
106 * This function will be called after sclp_early_facilities_detect(), which gets
107 * called from early.c code. The sclp_early_facilities_detect() function retrieves
108 * and saves the IPL information.
110 void __init
sclp_early_get_ipl_info(struct sclp_ipl_info
*info
)
112 *info
= sclp_ipl_info
;
115 int __init
sclp_early_get_core_info(struct sclp_core_info
*info
)
117 struct read_cpu_info_sccb
*sccb
;
118 int length
= test_facility(140) ? EXT_SCCB_READ_CPU
: PAGE_SIZE
;
121 if (!SCLP_HAS_CPU_INFO
)
124 sccb
= memblock_alloc_low(length
, PAGE_SIZE
);
128 memset(sccb
, 0, length
);
129 sccb
->header
.length
= length
;
130 sccb
->header
.control_mask
[2] = 0x80;
131 if (sclp_early_cmd(SCLP_CMDW_READ_CPU_INFO
, sccb
)) {
135 if (sccb
->header
.response_code
!= 0x0010) {
139 sclp_fill_core_info(info
, sccb
);
141 memblock_free_early((unsigned long)sccb
, length
);
145 static void __init
sclp_early_console_detect(struct init_sccb
*sccb
)
147 if (sccb
->header
.response_code
!= 0x20)
150 if (sclp_early_con_check_vt220(sccb
))
153 if (sclp_early_con_check_linemode(sccb
))
154 sclp
.has_linemode
= 1;
157 void __init
sclp_early_detect(void)
159 void *sccb
= sclp_early_sccb
;
161 sclp_early_facilities_detect();
164 * Turn off SCLP event notifications. Also save remote masks in the
165 * sccb. These are sufficient to detect sclp console capabilities.
167 sclp_early_set_event_mask(sccb
, 0, 0);
168 sclp_early_console_detect(sccb
);