1// SPDX-License-Identifier: GPL-2.0
2/*
3 *    Copyright IBM Corp. 2015
4 *    Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
5 */
6
7#include <linux/kernel.h>
8#include <asm/processor.h>
9#include <asm/lowcore.h>
10#include <asm/ctlreg.h>
11#include <asm/ebcdic.h>
12#include <asm/irq.h>
13#include <asm/sections.h>
14#include <asm/physmem_info.h>
15#include <asm/facility.h>
16#include "sclp.h"
17#include "sclp_rw.h"
18
19static struct read_info_sccb __bootdata(sclp_info_sccb);
20static int __bootdata(sclp_info_sccb_valid);
21char *__bootdata_preserved(sclp_early_sccb);
22int sclp_init_state = sclp_init_state_uninitialized;
23/*
24 * Used to keep track of the size of the event masks. Qemu until version 2.11
25 * only supports 4 and needs a workaround.
26 */
27bool sclp_mask_compat_mode;
28
29void sclp_early_wait_irq(void)
30{
31	unsigned long psw_mask, addr;
32	psw_t psw_ext_save, psw_wait;
33	union ctlreg0 cr0, cr0_new;
34
35	local_ctl_store(0, &cr0.reg);
36	cr0_new.val = cr0.val & ~CR0_IRQ_SUBCLASS_MASK;
37	cr0_new.lap = 0;
38	cr0_new.sssm = 1;
39	local_ctl_load(0, &cr0_new.reg);
40
41	psw_ext_save = S390_lowcore.external_new_psw;
42	psw_mask = __extract_psw();
43	S390_lowcore.external_new_psw.mask = psw_mask;
44	psw_wait.mask = psw_mask | PSW_MASK_EXT | PSW_MASK_WAIT;
45	S390_lowcore.ext_int_code = 0;
46
47	do {
48		asm volatile(
49			"	larl	%[addr],0f\n"
50			"	stg	%[addr],%[psw_wait_addr]\n"
51			"	stg	%[addr],%[psw_ext_addr]\n"
52			"	lpswe	%[psw_wait]\n"
53			"0:\n"
54			: [addr] "=&d" (addr),
55			  [psw_wait_addr] "=Q" (psw_wait.addr),
56			  [psw_ext_addr] "=Q" (S390_lowcore.external_new_psw.addr)
57			: [psw_wait] "Q" (psw_wait)
58			: "cc", "memory");
59	} while (S390_lowcore.ext_int_code != EXT_IRQ_SERVICE_SIG);
60
61	S390_lowcore.external_new_psw = psw_ext_save;
62	local_ctl_load(0, &cr0.reg);
63}
64
65int sclp_early_cmd(sclp_cmdw_t cmd, void *sccb)
66{
67	unsigned long flags;
68	int rc;
69
70	flags = arch_local_irq_save();
71	rc = sclp_service_call(cmd, sccb);
72	if (rc)
73		goto out;
74	sclp_early_wait_irq();
75out:
76	arch_local_irq_restore(flags);
77	return rc;
78}
79
80struct write_sccb {
81	struct sccb_header header;
82	struct msg_buf msg;
83} __packed;
84
85/* Output multi-line text using SCLP Message interface. */
86static void sclp_early_print_lm(const char *str, unsigned int len)
87{
88	unsigned char *ptr, *end, ch;
89	unsigned int count, offset;
90	struct write_sccb *sccb;
91	struct msg_buf *msg;
92	struct mdb *mdb;
93	struct mto *mto;
94	struct go *go;
95
96	sccb = (struct write_sccb *) sclp_early_sccb;
97	end = (unsigned char *) sccb + EARLY_SCCB_SIZE - 1;
98	memset(sccb, 0, sizeof(*sccb));
99	ptr = (unsigned char *) &sccb->msg.mdb.mto;
100	offset = 0;
101	do {
102		for (count = sizeof(*mto); offset < len; count++) {
103			ch = str[offset++];
104			if ((ch == 0x0a) || (ptr + count > end))
105				break;
106			ptr[count] = _ascebc[ch];
107		}
108		mto = (struct mto *) ptr;
109		memset(mto, 0, sizeof(*mto));
110		mto->length = count;
111		mto->type = 4;
112		mto->line_type_flags = LNTPFLGS_ENDTEXT;
113		ptr += count;
114	} while ((offset < len) && (ptr + sizeof(*mto) <= end));
115	len = ptr - (unsigned char *) sccb;
116	sccb->header.length = len - offsetof(struct write_sccb, header);
117	msg = &sccb->msg;
118	msg->header.type = EVTYP_MSG;
119	msg->header.length = len - offsetof(struct write_sccb, msg.header);
120	mdb = &msg->mdb;
121	mdb->header.type = 1;
122	mdb->header.tag = 0xD4C4C240;
123	mdb->header.revision_code = 1;
124	mdb->header.length = len - offsetof(struct write_sccb, msg.mdb.header);
125	go = &mdb->go;
126	go->length = sizeof(*go);
127	go->type = 1;
128	sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_DATA, sccb);
129}
130
131struct vt220_sccb {
132	struct sccb_header header;
133	struct {
134		struct evbuf_header header;
135		char data[];
136	} msg;
137} __packed;
138
139/* Output multi-line text using SCLP VT220 interface. */
140static void sclp_early_print_vt220(const char *str, unsigned int len)
141{
142	struct vt220_sccb *sccb;
143
144	sccb = (struct vt220_sccb *) sclp_early_sccb;
145	if (sizeof(*sccb) + len >= EARLY_SCCB_SIZE)
146		len = EARLY_SCCB_SIZE - sizeof(*sccb);
147	memset(sccb, 0, sizeof(*sccb));
148	memcpy(&sccb->msg.data, str, len);
149	sccb->header.length = sizeof(*sccb) + len;
150	sccb->msg.header.length = sizeof(sccb->msg) + len;
151	sccb->msg.header.type = EVTYP_VT220MSG;
152	sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_DATA, sccb);
153}
154
155int sclp_early_set_event_mask(struct init_sccb *sccb,
156			      sccb_mask_t receive_mask,
157			      sccb_mask_t send_mask)
158{
159retry:
160	memset(sccb, 0, sizeof(*sccb));
161	sccb->header.length = sizeof(*sccb);
162	if (sclp_mask_compat_mode)
163		sccb->mask_length = SCLP_MASK_SIZE_COMPAT;
164	else
165		sccb->mask_length = sizeof(sccb_mask_t);
166	sccb_set_recv_mask(sccb, receive_mask);
167	sccb_set_send_mask(sccb, send_mask);
168	if (sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_MASK, sccb))
169		return -EIO;
170	if ((sccb->header.response_code == 0x74f0) && !sclp_mask_compat_mode) {
171		sclp_mask_compat_mode = true;
172		goto retry;
173	}
174	if (sccb->header.response_code != 0x20)
175		return -EIO;
176	return 0;
177}
178
179unsigned int sclp_early_con_check_linemode(struct init_sccb *sccb)
180{
181	if (!(sccb_get_sclp_send_mask(sccb) & EVTYP_OPCMD_MASK))
182		return 0;
183	if (!(sccb_get_sclp_recv_mask(sccb) & (EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK)))
184		return 0;
185	return 1;
186}
187
188unsigned int sclp_early_con_check_vt220(struct init_sccb *sccb)
189{
190	if (sccb_get_sclp_send_mask(sccb) & EVTYP_VT220MSG_MASK)
191		return 1;
192	return 0;
193}
194
195static int sclp_early_setup(int disable, int *have_linemode, int *have_vt220)
196{
197	unsigned long receive_mask, send_mask;
198	struct init_sccb *sccb;
199	int rc;
200
201	BUILD_BUG_ON(sizeof(struct init_sccb) > PAGE_SIZE);
202
203	*have_linemode = *have_vt220 = 0;
204	sccb = (struct init_sccb *) sclp_early_sccb;
205	receive_mask = disable ? 0 : EVTYP_OPCMD_MASK;
206	send_mask = disable ? 0 : EVTYP_VT220MSG_MASK | EVTYP_MSG_MASK;
207	rc = sclp_early_set_event_mask(sccb, receive_mask, send_mask);
208	if (rc)
209		return rc;
210	*have_linemode = sclp_early_con_check_linemode(sccb);
211	*have_vt220 = !!(sccb_get_send_mask(sccb) & EVTYP_VT220MSG_MASK);
212	return rc;
213}
214
215void sclp_early_set_buffer(void *sccb)
216{
217	sclp_early_sccb = sccb;
218}
219
220/*
221 * Output one or more lines of text on the SCLP console (VT220 and /
222 * or line-mode).
223 */
224void __sclp_early_printk(const char *str, unsigned int len)
225{
226	int have_linemode, have_vt220;
227
228	if (sclp_init_state != sclp_init_state_uninitialized)
229		return;
230	if (sclp_early_setup(0, &have_linemode, &have_vt220) != 0)
231		return;
232	if (have_linemode)
233		sclp_early_print_lm(str, len);
234	if (have_vt220)
235		sclp_early_print_vt220(str, len);
236	sclp_early_setup(1, &have_linemode, &have_vt220);
237}
238
239void sclp_early_printk(const char *str)
240{
241	__sclp_early_printk(str, strlen(str));
242}
243
244/*
245 * Use sclp_emergency_printk() to print a string when the system is in a
246 * state where regular console drivers cannot be assumed to work anymore.
247 *
248 * Callers must make sure that no concurrent SCLP requests are outstanding
249 * and all other CPUs are stopped, or at least disabled for external
250 * interrupts.
251 */
252void sclp_emergency_printk(const char *str)
253{
254	int have_linemode, have_vt220;
255	unsigned int len;
256
257	len = strlen(str);
258	/*
259	 * Don't care about return values; if requests fail, just ignore and
260	 * continue to have a rather high chance that anything is printed.
261	 */
262	sclp_early_setup(0, &have_linemode, &have_vt220);
263	sclp_early_print_lm(str, len);
264	sclp_early_print_vt220(str, len);
265	sclp_early_setup(1, &have_linemode, &have_vt220);
266}
267
268/*
269 * We can't pass sclp_info_sccb to sclp_early_cmd() here directly,
270 * because it might not fulfil the requiremets for a SCLP communication buffer:
271 *   - lie below 2G in memory
272 *   - be page-aligned
273 * Therefore, we use the buffer sclp_early_sccb (which fulfils all those
274 * requirements) temporarily for communication and copy a received response
275 * back into the buffer sclp_info_sccb upon successful completion.
276 */
277int __init sclp_early_read_info(void)
278{
279	int i;
280	int length = test_facility(140) ? EXT_SCCB_READ_SCP : PAGE_SIZE;
281	struct read_info_sccb *sccb = (struct read_info_sccb *)sclp_early_sccb;
282	sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED,
283				  SCLP_CMDW_READ_SCP_INFO};
284
285	for (i = 0; i < ARRAY_SIZE(commands); i++) {
286		memset(sccb, 0, length);
287		sccb->header.length = length;
288		sccb->header.function_code = 0x80;
289		sccb->header.control_mask[2] = 0x80;
290		if (sclp_early_cmd(commands[i], sccb))
291			break;
292		if (sccb->header.response_code == 0x10) {
293			memcpy(&sclp_info_sccb, sccb, length);
294			sclp_info_sccb_valid = 1;
295			return 0;
296		}
297		if (sccb->header.response_code != 0x1f0)
298			break;
299	}
300	return -EIO;
301}
302
303struct read_info_sccb * __init sclp_early_get_info(void)
304{
305	if (!sclp_info_sccb_valid)
306		return NULL;
307
308	return &sclp_info_sccb;
309}
310
311int __init sclp_early_get_memsize(unsigned long *mem)
312{
313	unsigned long rnmax;
314	unsigned long rnsize;
315	struct read_info_sccb *sccb = &sclp_info_sccb;
316
317	if (!sclp_info_sccb_valid)
318		return -EIO;
319
320	rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2;
321	rnsize = sccb->rnsize ? sccb->rnsize : sccb->rnsize2;
322	rnsize <<= 20;
323	*mem = rnsize * rnmax;
324	return 0;
325}
326
327int __init sclp_early_get_hsa_size(unsigned long *hsa_size)
328{
329	if (!sclp_info_sccb_valid)
330		return -EIO;
331
332	*hsa_size = 0;
333	if (sclp_info_sccb.hsa_size)
334		*hsa_size = (sclp_info_sccb.hsa_size - 1) * PAGE_SIZE;
335	return 0;
336}
337
338#define SCLP_STORAGE_INFO_FACILITY     0x0000400000000000UL
339
340void __weak __init add_physmem_online_range(u64 start, u64 end) {}
341int __init sclp_early_read_storage_info(void)
342{
343	struct read_storage_sccb *sccb = (struct read_storage_sccb *)sclp_early_sccb;
344	int rc, id, max_id = 0;
345	unsigned long rn, rzm;
346	sclp_cmdw_t command;
347	u16 sn;
348
349	if (!sclp_info_sccb_valid)
350		return -EIO;
351
352	if (!(sclp_info_sccb.facilities & SCLP_STORAGE_INFO_FACILITY))
353		return -EOPNOTSUPP;
354
355	rzm = sclp_info_sccb.rnsize ?: sclp_info_sccb.rnsize2;
356	rzm <<= 20;
357
358	for (id = 0; id <= max_id; id++) {
359		memset(sclp_early_sccb, 0, EARLY_SCCB_SIZE);
360		sccb->header.length = EARLY_SCCB_SIZE;
361		command = SCLP_CMDW_READ_STORAGE_INFO | (id << 8);
362		rc = sclp_early_cmd(command, sccb);
363		if (rc)
364			goto fail;
365
366		max_id = sccb->max_id;
367		switch (sccb->header.response_code) {
368		case 0x0010:
369			for (sn = 0; sn < sccb->assigned; sn++) {
370				if (!sccb->entries[sn])
371					continue;
372				rn = sccb->entries[sn] >> 16;
373				add_physmem_online_range((rn - 1) * rzm, rn * rzm);
374			}
375			break;
376		case 0x0310:
377		case 0x0410:
378			break;
379		default:
380			goto fail;
381		}
382	}
383
384	return 0;
385fail:
386	physmem_info.range_count = 0;
387	return -EIO;
388}
389