blob: b57fe0efb4227d14836ac007d65e57d1168f5530 [file] [log] [blame]
Michael Holzheue657d8f2013-11-13 10:38:27 +01001/*
2 * SCLP early driver
3 *
4 * Copyright IBM Corp. 2013
5 */
6
7#define KMSG_COMPONENT "sclp_early"
8#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
9
Michael Holzheuacf6a002013-11-13 10:38:27 +010010#include <asm/ctl_reg.h>
Michael Holzheue657d8f2013-11-13 10:38:27 +010011#include <asm/sclp.h>
12#include <asm/ipl.h>
13#include "sclp_sdias.h"
14#include "sclp.h"
15
Michael Holzheuacf6a002013-11-13 10:38:27 +010016#define SCLP_CMDW_READ_SCP_INFO 0x00020001
17#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001
18
19struct read_info_sccb {
20 struct sccb_header header; /* 0-7 */
21 u16 rnmax; /* 8-9 */
22 u8 rnsize; /* 10 */
Heiko Carstenscf813db2014-03-10 14:50:16 +010023 u8 _reserved0[16 - 11]; /* 11-15 */
24 u16 ncpurl; /* 16-17 */
Heiko Carstens217a4402013-12-30 12:54:14 +010025 u16 cpuoff; /* 18-19 */
26 u8 _reserved7[24 - 20]; /* 20-23 */
Michael Holzheuacf6a002013-11-13 10:38:27 +010027 u8 loadparm[8]; /* 24-31 */
28 u8 _reserved1[48 - 32]; /* 32-47 */
29 u64 facilities; /* 48-55 */
30 u8 _reserved2[84 - 56]; /* 56-83 */
31 u8 fac84; /* 84 */
32 u8 fac85; /* 85 */
33 u8 _reserved3[91 - 86]; /* 86-90 */
34 u8 flags; /* 91 */
35 u8 _reserved4[100 - 92]; /* 92-99 */
36 u32 rnsize2; /* 100-103 */
37 u64 rnmax2; /* 104-111 */
Heiko Carstenscf813db2014-03-10 14:50:16 +010038 u8 _reserved5[120 - 112]; /* 112-119 */
39 u16 hcpua; /* 120-121 */
40 u8 _reserved6[4096 - 122]; /* 122-4095 */
Michael Holzheuacf6a002013-11-13 10:38:27 +010041} __packed __aligned(PAGE_SIZE);
42
Hendrik Brueckner56e57a82013-12-05 19:03:50 +010043static char sccb_early[PAGE_SIZE] __aligned(PAGE_SIZE) __initdata;
Hendrik Brueckner52733e02013-12-05 19:28:39 +010044static unsigned int sclp_con_has_vt220 __initdata;
45static unsigned int sclp_con_has_linemode __initdata;
Michael Holzheue657d8f2013-11-13 10:38:27 +010046static unsigned long sclp_hsa_size;
Heiko Carstenscf813db2014-03-10 14:50:16 +010047static unsigned int sclp_max_cpu;
Hendrik Brueckner333cce92013-12-05 18:46:51 +010048static struct sclp_ipl_info sclp_ipl_info;
Heiko Carstens217a4402013-12-30 12:54:14 +010049static unsigned char sclp_siif;
Michael Holzheue657d8f2013-11-13 10:38:27 +010050
Michael Holzheuacf6a002013-11-13 10:38:27 +010051u64 sclp_facilities;
52u8 sclp_fac84;
53unsigned long long sclp_rzm;
54unsigned long long sclp_rnmax;
55
56static int __init sclp_cmd_sync_early(sclp_cmdw_t cmd, void *sccb)
57{
58 int rc;
59
60 __ctl_set_bit(0, 9);
61 rc = sclp_service_call(cmd, sccb);
62 if (rc)
63 goto out;
64 __load_psw_mask(PSW_DEFAULT_KEY | PSW_MASK_BASE | PSW_MASK_EA |
65 PSW_MASK_BA | PSW_MASK_EXT | PSW_MASK_WAIT);
66 local_irq_disable();
67out:
68 /* Contents of the sccb might have changed. */
69 barrier();
70 __ctl_clear_bit(0, 9);
71 return rc;
72}
73
Hendrik Brueckner56e57a82013-12-05 19:03:50 +010074static int __init sclp_read_info_early(struct read_info_sccb *sccb)
Michael Holzheuacf6a002013-11-13 10:38:27 +010075{
Hendrik Brueckner333cce92013-12-05 18:46:51 +010076 int rc, i;
Michael Holzheuacf6a002013-11-13 10:38:27 +010077 sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED,
78 SCLP_CMDW_READ_SCP_INFO};
79
Michael Holzheuacf6a002013-11-13 10:38:27 +010080 for (i = 0; i < ARRAY_SIZE(commands); i++) {
81 do {
82 memset(sccb, 0, sizeof(*sccb));
83 sccb->header.length = sizeof(*sccb);
84 sccb->header.function_code = 0x80;
85 sccb->header.control_mask[2] = 0x80;
86 rc = sclp_cmd_sync_early(commands[i], sccb);
87 } while (rc == -EBUSY);
88
89 if (rc)
90 break;
Hendrik Brueckner333cce92013-12-05 18:46:51 +010091 if (sccb->header.response_code == 0x10)
92 return 0;
Michael Holzheuacf6a002013-11-13 10:38:27 +010093 if (sccb->header.response_code != 0x1f0)
94 break;
95 }
Hendrik Brueckner333cce92013-12-05 18:46:51 +010096 return -EIO;
Michael Holzheuacf6a002013-11-13 10:38:27 +010097}
98
Hendrik Brueckner5d5de1a2013-12-05 19:13:36 +010099static void __init sclp_facilities_detect(struct read_info_sccb *sccb)
Michael Holzheuacf6a002013-11-13 10:38:27 +0100100{
Heiko Carstens217a4402013-12-30 12:54:14 +0100101 struct sclp_cpu_entry *cpue;
102 u16 boot_cpu_address, cpu;
103
Hendrik Brueckner56e57a82013-12-05 19:03:50 +0100104 if (sclp_read_info_early(sccb))
Michael Holzheuacf6a002013-11-13 10:38:27 +0100105 return;
106
Michael Holzheuacf6a002013-11-13 10:38:27 +0100107 sclp_facilities = sccb->facilities;
108 sclp_fac84 = sccb->fac84;
109 if (sccb->fac85 & 0x02)
110 S390_lowcore.machine_flags |= MACHINE_FLAG_ESOP;
111 sclp_rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2;
112 sclp_rzm = sccb->rnsize ? sccb->rnsize : sccb->rnsize2;
113 sclp_rzm <<= 20;
Hendrik Brueckner333cce92013-12-05 18:46:51 +0100114
Heiko Carstenscf813db2014-03-10 14:50:16 +0100115 if (!sccb->hcpua) {
116 if (MACHINE_IS_VM)
117 sclp_max_cpu = 64;
118 else
119 sclp_max_cpu = sccb->ncpurl;
120 } else {
121 sclp_max_cpu = sccb->hcpua + 1;
122 }
123
Heiko Carstens217a4402013-12-30 12:54:14 +0100124 boot_cpu_address = stap();
125 cpue = (void *)sccb + sccb->cpuoff;
126 for (cpu = 0; cpu < sccb->ncpurl; cpue++, cpu++) {
127 if (boot_cpu_address != cpue->address)
128 continue;
129 sclp_siif = cpue->siif;
130 break;
131 }
132
Hendrik Brueckner333cce92013-12-05 18:46:51 +0100133 /* Save IPL information */
134 sclp_ipl_info.is_valid = 1;
135 if (sccb->flags & 0x2)
136 sclp_ipl_info.has_dump = 1;
137 memcpy(&sclp_ipl_info.loadparm, &sccb->loadparm, LOADPARM_LEN);
Michael Holzheuacf6a002013-11-13 10:38:27 +0100138}
139
140bool __init sclp_has_linemode(void)
141{
Hendrik Brueckner52733e02013-12-05 19:28:39 +0100142 return !!sclp_con_has_linemode;
Michael Holzheuacf6a002013-11-13 10:38:27 +0100143}
144
145bool __init sclp_has_vt220(void)
146{
Hendrik Brueckner52733e02013-12-05 19:28:39 +0100147 return !!sclp_con_has_vt220;
Michael Holzheuacf6a002013-11-13 10:38:27 +0100148}
149
150unsigned long long sclp_get_rnmax(void)
151{
152 return sclp_rnmax;
153}
154
155unsigned long long sclp_get_rzm(void)
156{
157 return sclp_rzm;
158}
159
Heiko Carstenscf813db2014-03-10 14:50:16 +0100160unsigned int sclp_get_max_cpu(void)
161{
162 return sclp_max_cpu;
163}
164
Heiko Carstens217a4402013-12-30 12:54:14 +0100165int sclp_has_siif(void)
166{
167 return sclp_siif;
168}
169EXPORT_SYMBOL(sclp_has_siif);
170
Michael Holzheuacf6a002013-11-13 10:38:27 +0100171/*
172 * This function will be called after sclp_facilities_detect(), which gets
Hendrik Brueckner333cce92013-12-05 18:46:51 +0100173 * called from early.c code. The sclp_facilities_detect() function retrieves
174 * and saves the IPL information.
Michael Holzheuacf6a002013-11-13 10:38:27 +0100175 */
176void __init sclp_get_ipl_info(struct sclp_ipl_info *info)
177{
Hendrik Brueckner333cce92013-12-05 18:46:51 +0100178 *info = sclp_ipl_info;
Michael Holzheuacf6a002013-11-13 10:38:27 +0100179}
180
Michael Holzheue657d8f2013-11-13 10:38:27 +0100181static int __init sclp_cmd_early(sclp_cmdw_t cmd, void *sccb)
182{
183 int rc;
184
185 do {
186 rc = sclp_cmd_sync_early(cmd, sccb);
187 } while (rc == -EBUSY);
188
189 if (rc)
190 return -EIO;
191 if (((struct sccb_header *) sccb)->response_code != 0x0020)
192 return -EIO;
193 return 0;
194}
195
196static void __init sccb_init_eq_size(struct sdias_sccb *sccb)
197{
198 memset(sccb, 0, sizeof(*sccb));
199
200 sccb->hdr.length = sizeof(*sccb);
201 sccb->evbuf.hdr.length = sizeof(struct sdias_evbuf);
202 sccb->evbuf.hdr.type = EVTYP_SDIAS;
203 sccb->evbuf.event_qual = SDIAS_EQ_SIZE;
204 sccb->evbuf.data_id = SDIAS_DI_FCP_DUMP;
205 sccb->evbuf.event_id = 4712;
206 sccb->evbuf.dbs = 1;
207}
208
Hendrik Brueckner5d5de1a2013-12-05 19:13:36 +0100209static int __init sclp_set_event_mask(struct init_sccb *sccb,
210 unsigned long receive_mask,
Michael Holzheue657d8f2013-11-13 10:38:27 +0100211 unsigned long send_mask)
212{
Michael Holzheue657d8f2013-11-13 10:38:27 +0100213 memset(sccb, 0, sizeof(*sccb));
214 sccb->header.length = sizeof(*sccb);
215 sccb->mask_length = sizeof(sccb_mask_t);
216 sccb->receive_mask = receive_mask;
217 sccb->send_mask = send_mask;
218 return sclp_cmd_early(SCLP_CMDW_WRITE_EVENT_MASK, sccb);
219}
220
Hendrik Brueckner5d5de1a2013-12-05 19:13:36 +0100221static long __init sclp_hsa_size_init(struct sdias_sccb *sccb)
Michael Holzheue657d8f2013-11-13 10:38:27 +0100222{
Michael Holzheue657d8f2013-11-13 10:38:27 +0100223 sccb_init_eq_size(sccb);
224 if (sclp_cmd_early(SCLP_CMDW_WRITE_EVENT_DATA, sccb))
225 return -EIO;
Michael Holzheu94999342014-02-24 14:30:00 +0100226 if (sccb->evbuf.blk_cnt == 0)
227 return 0;
228 return (sccb->evbuf.blk_cnt - 1) * PAGE_SIZE;
Michael Holzheue657d8f2013-11-13 10:38:27 +0100229}
230
Hendrik Brueckner5d5de1a2013-12-05 19:13:36 +0100231static long __init sclp_hsa_copy_wait(struct sccb_header *sccb)
Michael Holzheue657d8f2013-11-13 10:38:27 +0100232{
Michael Holzheue657d8f2013-11-13 10:38:27 +0100233 memset(sccb, 0, PAGE_SIZE);
234 sccb->length = PAGE_SIZE;
235 if (sclp_cmd_early(SCLP_CMDW_READ_EVENT_DATA, sccb))
236 return -EIO;
Michael Holzheu94999342014-02-24 14:30:00 +0100237 if (((struct sdias_sccb *) sccb)->evbuf.blk_cnt == 0)
238 return 0;
Michael Holzheue657d8f2013-11-13 10:38:27 +0100239 return (((struct sdias_sccb *) sccb)->evbuf.blk_cnt - 1) * PAGE_SIZE;
240}
241
242unsigned long sclp_get_hsa_size(void)
243{
244 return sclp_hsa_size;
245}
246
Hendrik Brueckner5d5de1a2013-12-05 19:13:36 +0100247static void __init sclp_hsa_size_detect(void *sccb)
Michael Holzheue657d8f2013-11-13 10:38:27 +0100248{
249 long size;
250
251 /* First try synchronous interface (LPAR) */
Hendrik Brueckner5d5de1a2013-12-05 19:13:36 +0100252 if (sclp_set_event_mask(sccb, 0, 0x40000010))
Michael Holzheue657d8f2013-11-13 10:38:27 +0100253 return;
Hendrik Brueckner5d5de1a2013-12-05 19:13:36 +0100254 size = sclp_hsa_size_init(sccb);
Michael Holzheue657d8f2013-11-13 10:38:27 +0100255 if (size < 0)
256 return;
257 if (size != 0)
258 goto out;
259 /* Then try asynchronous interface (z/VM) */
Hendrik Brueckner5d5de1a2013-12-05 19:13:36 +0100260 if (sclp_set_event_mask(sccb, 0x00000010, 0x40000010))
Michael Holzheue657d8f2013-11-13 10:38:27 +0100261 return;
Hendrik Brueckner5d5de1a2013-12-05 19:13:36 +0100262 size = sclp_hsa_size_init(sccb);
Michael Holzheue657d8f2013-11-13 10:38:27 +0100263 if (size < 0)
264 return;
Hendrik Brueckner5d5de1a2013-12-05 19:13:36 +0100265 size = sclp_hsa_copy_wait(sccb);
Michael Holzheue657d8f2013-11-13 10:38:27 +0100266 if (size < 0)
267 return;
268out:
Michael Holzheue657d8f2013-11-13 10:38:27 +0100269 sclp_hsa_size = size;
270}
Michael Holzheu7b50da52013-11-13 10:38:27 +0100271
Hendrik Brueckner52733e02013-12-05 19:28:39 +0100272static unsigned int __init sclp_con_check_linemode(struct init_sccb *sccb)
273{
274 if (!(sccb->sclp_send_mask & (EVTYP_OPCMD_MASK | EVTYP_PMSGCMD_MASK)))
275 return 0;
276 if (!(sccb->sclp_receive_mask & (EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK)))
277 return 0;
278 return 1;
279}
280
281static void __init sclp_console_detect(struct init_sccb *sccb)
282{
283 if (sccb->header.response_code != 0x20)
284 return;
285
286 if (sccb->sclp_send_mask & EVTYP_VT220MSG_MASK)
287 sclp_con_has_vt220 = 1;
288
289 if (sclp_con_check_linemode(sccb))
290 sclp_con_has_linemode = 1;
291}
292
Michael Holzheu7b50da52013-11-13 10:38:27 +0100293void __init sclp_early_detect(void)
294{
Hendrik Brueckner5d5de1a2013-12-05 19:13:36 +0100295 void *sccb = &sccb_early;
296
297 sclp_facilities_detect(sccb);
298 sclp_hsa_size_detect(sccb);
Hendrik Brueckner52733e02013-12-05 19:28:39 +0100299
300 /* Turn off SCLP event notifications. Also save remote masks in the
301 * sccb. These are sufficient to detect sclp console capabilities.
302 */
Hendrik Brueckner5d5de1a2013-12-05 19:13:36 +0100303 sclp_set_event_mask(sccb, 0, 0);
Hendrik Brueckner52733e02013-12-05 19:28:39 +0100304 sclp_console_detect(sccb);
Michael Holzheu7b50da52013-11-13 10:38:27 +0100305}