1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2e657d8feSMichael Holzheu /*
3e657d8feSMichael Holzheu * SCLP early driver
4e657d8feSMichael Holzheu *
5e657d8feSMichael Holzheu * Copyright IBM Corp. 2013
6e657d8feSMichael Holzheu */
7e657d8feSMichael Holzheu
8e657d8feSMichael Holzheu #define KMSG_COMPONENT "sclp_early"
9e657d8feSMichael Holzheu #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
10e657d8feSMichael Holzheu
11a313bdc5SSebastian Ott #include <linux/errno.h>
1208ab919dSSumanth Korikkar #include <linux/memblock.h>
13acf6a004SMichael Holzheu #include <asm/ctl_reg.h>
14e657d8feSMichael Holzheu #include <asm/sclp.h>
15e657d8feSMichael Holzheu #include <asm/ipl.h>
1608ab919dSSumanth Korikkar #include <asm/setup.h>
17b971cbd0SSumanth Korikkar #include <asm/facility.h>
18e657d8feSMichael Holzheu #include "sclp_sdias.h"
19e657d8feSMichael Holzheu #include "sclp.h"
20e657d8feSMichael Holzheu
21333cce91SHendrik Brueckner static struct sclp_ipl_info sclp_ipl_info;
22e657d8feSMichael Holzheu
2337c5f6c8SDavid Hildenbrand struct sclp_info sclp;
2437c5f6c8SDavid Hildenbrand EXPORT_SYMBOL(sclp);
25acf6a004SMichael Holzheu
sclp_early_facilities_detect(void)26d25d23e1SSumanth Korikkar static void __init sclp_early_facilities_detect(void)
27acf6a004SMichael Holzheu {
28d08d9430SMartin Schwidefsky struct sclp_core_entry *cpue;
29d25d23e1SSumanth Korikkar struct read_info_sccb *sccb;
30217a4406SHeiko Carstens u16 boot_cpu_address, cpu;
31217a4406SHeiko Carstens
32d25d23e1SSumanth Korikkar sccb = sclp_early_get_info();
33d25d23e1SSumanth Korikkar if (!sccb)
34acf6a004SMichael Holzheu return;
35acf6a004SMichael Holzheu
3678335a30SDavid Hildenbrand sclp.facilities = sccb->facilities;
3737c5f6c8SDavid Hildenbrand sclp.has_sprp = !!(sccb->fac84 & 0x02);
38d08d9430SMartin Schwidefsky sclp.has_core_type = !!(sccb->fac84 & 0x01);
395236c751SDavid Hildenbrand sclp.has_gsls = !!(sccb->fac85 & 0x80);
404013ade3SDavid Hildenbrand sclp.has_64bscao = !!(sccb->fac116 & 0x80);
4109be9cb9SDavid Hildenbrand sclp.has_cmma = !!(sccb->fac116 & 0x40);
42f7ba1d34SEugene (jno) Dvurechenski sclp.has_esca = !!(sccb->fac116 & 0x08);
43a0eb55e6SDavid Hildenbrand sclp.has_pfmfi = !!(sccb->fac117 & 0x40);
449c375490SDavid Hildenbrand sclp.has_ibs = !!(sccb->fac117 & 0x20);
459e73ea70SMichael Mueller sclp.has_gisaf = !!(sccb->fac118 & 0x08);
46f7ba1d34SEugene (jno) Dvurechenski sclp.has_hvs = !!(sccb->fac119 & 0x80);
4771cb1bf6SFarhan Ali sclp.has_kss = !!(sccb->fac98 & 0x01);
489db153f4SMatthew Rosato sclp.has_aisii = !!(sccb->fac118 & 0x40);
49efef0db7SMatthew Rosato sclp.has_aeni = !!(sccb->fac118 & 0x20);
50b05a870cSMatthew Rosato sclp.has_aisi = !!(sccb->fac118 & 0x10);
51e3d27b62SMatthew Rosato sclp.has_zpci_lsi = !!(sccb->fac118 & 0x01);
52acf6a004SMichael Holzheu if (sccb->fac85 & 0x02)
53acf6a004SMichael Holzheu S390_lowcore.machine_flags |= MACHINE_FLAG_ESOP;
54118bd31bSMartin Schwidefsky if (sccb->fac91 & 0x40)
55118bd31bSMartin Schwidefsky S390_lowcore.machine_flags |= MACHINE_FLAG_TLB_GUEST;
561b553839SAlexander Egorenkov if (sccb->cpuoff > 134) {
574ad78b86SCollin Walling sclp.has_diag318 = !!(sccb->byte_134 & 0x80);
58*8cf57d72SAnastasia Eskova sclp.has_diag320 = !!(sccb->byte_134 & 0x04);
591b553839SAlexander Egorenkov sclp.has_iplcc = !!(sccb->byte_134 & 0x02);
601b553839SAlexander Egorenkov }
6187fd22e0SSven Schnelle if (sccb->cpuoff > 137) {
62d76b14f3SAlexander Egorenkov sclp.has_sipl = !!(sccb->cbl & 0x4000);
6387fd22e0SSven Schnelle sclp.has_sipl_eckd = !!(sccb->cbl & 0x2000);
6487fd22e0SSven Schnelle }
6537c5f6c8SDavid Hildenbrand sclp.rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2;
6637c5f6c8SDavid Hildenbrand sclp.rzm = sccb->rnsize ? sccb->rnsize : sccb->rnsize2;
6737c5f6c8SDavid Hildenbrand sclp.rzm <<= 20;
6837c5f6c8SDavid Hildenbrand sclp.ibc = sccb->ibc;
69333cce91SHendrik Brueckner
7032e6b236SGuenther Hutzl if (sccb->hamaxpow && sccb->hamaxpow < 64)
7132e6b236SGuenther Hutzl sclp.hamax = (1UL << sccb->hamaxpow) - 1;
7232e6b236SGuenther Hutzl else
7332e6b236SGuenther Hutzl sclp.hamax = U64_MAX;
7432e6b236SGuenther Hutzl
75cf813db0SHeiko Carstens if (!sccb->hcpua) {
76cf813db0SHeiko Carstens if (MACHINE_IS_VM)
77d08d9430SMartin Schwidefsky sclp.max_cores = 64;
78cf813db0SHeiko Carstens else
79d08d9430SMartin Schwidefsky sclp.max_cores = sccb->ncpurl;
80cf813db0SHeiko Carstens } else {
81d08d9430SMartin Schwidefsky sclp.max_cores = sccb->hcpua + 1;
82cf813db0SHeiko Carstens }
83cf813db0SHeiko Carstens
84217a4406SHeiko Carstens boot_cpu_address = stap();
85217a4406SHeiko Carstens cpue = (void *)sccb + sccb->cpuoff;
86217a4406SHeiko Carstens for (cpu = 0; cpu < sccb->ncpurl; cpue++, cpu++) {
8710ad34bcSMartin Schwidefsky if (boot_cpu_address != cpue->core_id)
88217a4406SHeiko Carstens continue;
8937c5f6c8SDavid Hildenbrand sclp.has_siif = cpue->siif;
9037c5f6c8SDavid Hildenbrand sclp.has_sigpif = cpue->sigpif;
918dfd523fSDavid Hildenbrand sclp.has_sief2 = cpue->sief2;
92b9e28897SDavid Hildenbrand sclp.has_gpere = cpue->gpere;
9372cd82b9SDavid Hildenbrand sclp.has_ib = cpue->ib;
944a5c3e08SDavid Hildenbrand sclp.has_cei = cpue->cei;
9523861451SDavid Hildenbrand sclp.has_skey = cpue->skey;
96217a4406SHeiko Carstens break;
97217a4406SHeiko Carstens }
98217a4406SHeiko Carstens
99333cce91SHendrik Brueckner /* Save IPL information */
100333cce91SHendrik Brueckner sclp_ipl_info.is_valid = 1;
101118bd31bSMartin Schwidefsky if (sccb->fac91 & 0x2)
102333cce91SHendrik Brueckner sclp_ipl_info.has_dump = 1;
103333cce91SHendrik Brueckner memcpy(&sclp_ipl_info.loadparm, &sccb->loadparm, LOADPARM_LEN);
10410ad34bcSMartin Schwidefsky
1053b076dcaSVasily Gorbik if (sccb->hsa_size)
1063b076dcaSVasily Gorbik sclp.hsa_size = (sccb->hsa_size - 1) * PAGE_SIZE;
10737c5f6c8SDavid Hildenbrand sclp.mtid = (sccb->fac42 & 0x80) ? (sccb->fac42 & 31) : 0;
10837c5f6c8SDavid Hildenbrand sclp.mtid_cp = (sccb->fac42 & 0x80) ? (sccb->fac43 & 31) : 0;
10937c5f6c8SDavid Hildenbrand sclp.mtid_prev = (sccb->fac42 & 0x80) ? (sccb->fac66 & 31) : 0;
110154fa27eSAlexander Yarygin
111154fa27eSAlexander Yarygin sclp.hmfai = sccb->hmfai;
1120a9fddfaSSebastian Ott sclp.has_dirq = !!(sccb->cpudirq & 0x80);
113acf6a004SMichael Holzheu }
114acf6a004SMichael Holzheu
115acf6a004SMichael Holzheu /*
116d5ab7a34SHeiko Carstens * This function will be called after sclp_early_facilities_detect(), which gets
117d5ab7a34SHeiko Carstens * called from early.c code. The sclp_early_facilities_detect() function retrieves
118333cce91SHendrik Brueckner * and saves the IPL information.
119acf6a004SMichael Holzheu */
sclp_early_get_ipl_info(struct sclp_ipl_info * info)120d5ab7a34SHeiko Carstens void __init sclp_early_get_ipl_info(struct sclp_ipl_info *info)
121acf6a004SMichael Holzheu {
122333cce91SHendrik Brueckner *info = sclp_ipl_info;
123acf6a004SMichael Holzheu }
124acf6a004SMichael Holzheu
sclp_early_get_core_info(struct sclp_core_info * info)125d5ab7a34SHeiko Carstens int __init sclp_early_get_core_info(struct sclp_core_info *info)
126af51160eSHeiko Carstens {
12708ab919dSSumanth Korikkar struct read_cpu_info_sccb *sccb;
128b971cbd0SSumanth Korikkar int length = test_facility(140) ? EXT_SCCB_READ_CPU : PAGE_SIZE;
12908ab919dSSumanth Korikkar int rc = 0;
13008ab919dSSumanth Korikkar
13108ab919dSSumanth Korikkar if (!SCLP_HAS_CPU_INFO)
13208ab919dSSumanth Korikkar return -EOPNOTSUPP;
13308ab919dSSumanth Korikkar
13408ab919dSSumanth Korikkar sccb = memblock_alloc_low(length, PAGE_SIZE);
13508ab919dSSumanth Korikkar if (!sccb)
13608ab919dSSumanth Korikkar return -ENOMEM;
13708ab919dSSumanth Korikkar
13808ab919dSSumanth Korikkar memset(sccb, 0, length);
13908ab919dSSumanth Korikkar sccb->header.length = length;
14008ab919dSSumanth Korikkar sccb->header.control_mask[2] = 0x80;
14108ab919dSSumanth Korikkar if (sclp_early_cmd(SCLP_CMDW_READ_CPU_INFO, sccb)) {
14208ab919dSSumanth Korikkar rc = -EIO;
14308ab919dSSumanth Korikkar goto out;
14408ab919dSSumanth Korikkar }
14508ab919dSSumanth Korikkar if (sccb->header.response_code != 0x0010) {
14608ab919dSSumanth Korikkar rc = -EIO;
14708ab919dSSumanth Korikkar goto out;
14808ab919dSSumanth Korikkar }
14908ab919dSSumanth Korikkar sclp_fill_core_info(info, sccb);
15008ab919dSSumanth Korikkar out:
151b6b486ecSHeiko Carstens memblock_free(sccb, length);
15208ab919dSSumanth Korikkar return rc;
153af51160eSHeiko Carstens }
154af51160eSHeiko Carstens
sclp_early_console_detect(struct init_sccb * sccb)155d5ab7a34SHeiko Carstens static void __init sclp_early_console_detect(struct init_sccb *sccb)
15652733e01SHendrik Brueckner {
15752733e01SHendrik Brueckner if (sccb->header.response_code != 0x20)
15852733e01SHendrik Brueckner return;
15952733e01SHendrik Brueckner
160b8435635SClaudio Imbrenda if (sclp_early_con_check_vt220(sccb))
16137c5f6c8SDavid Hildenbrand sclp.has_vt220 = 1;
16252733e01SHendrik Brueckner
163d5ab7a34SHeiko Carstens if (sclp_early_con_check_linemode(sccb))
16437c5f6c8SDavid Hildenbrand sclp.has_linemode = 1;
16552733e01SHendrik Brueckner }
16652733e01SHendrik Brueckner
sclp_early_adjust_va(void)167639886b7SAlexander Gordeev void __init __no_sanitize_address sclp_early_adjust_va(void)
168ada1da31SAlexander Gordeev {
169ada1da31SAlexander Gordeev sclp_early_sccb = __va((unsigned long)sclp_early_sccb);
170ada1da31SAlexander Gordeev }
171ada1da31SAlexander Gordeev
sclp_early_detect(void)1727b50da53SMichael Holzheu void __init sclp_early_detect(void)
1737b50da53SMichael Holzheu {
174087c4d74SGerald Schaefer void *sccb = sclp_early_sccb;
1755d5de1a0SHendrik Brueckner
176d25d23e1SSumanth Korikkar sclp_early_facilities_detect();
17752733e01SHendrik Brueckner
178d5ab7a34SHeiko Carstens /*
179d5ab7a34SHeiko Carstens * Turn off SCLP event notifications. Also save remote masks in the
18052733e01SHendrik Brueckner * sccb. These are sufficient to detect sclp console capabilities.
18152733e01SHendrik Brueckner */
182d5ab7a34SHeiko Carstens sclp_early_set_event_mask(sccb, 0, 0);
183d5ab7a34SHeiko Carstens sclp_early_console_detect(sccb);
1847b50da53SMichael Holzheu }
185