162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Channel subsystem I/O instructions.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/export.h>
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <asm/asm-extable.h>
962306a36Sopenharmony_ci#include <asm/chpid.h>
1062306a36Sopenharmony_ci#include <asm/schid.h>
1162306a36Sopenharmony_ci#include <asm/crw.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include "ioasm.h"
1462306a36Sopenharmony_ci#include "orb.h"
1562306a36Sopenharmony_ci#include "cio.h"
1662306a36Sopenharmony_ci#include "cio_inject.h"
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_cistatic inline int __stsch(struct subchannel_id schid, struct schib *addr)
1962306a36Sopenharmony_ci{
2062306a36Sopenharmony_ci	unsigned long r1 = *(unsigned int *)&schid;
2162306a36Sopenharmony_ci	int ccode = -EIO;
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci	asm volatile(
2462306a36Sopenharmony_ci		"	lgr	1,%[r1]\n"
2562306a36Sopenharmony_ci		"	stsch	%[addr]\n"
2662306a36Sopenharmony_ci		"0:	ipm	%[cc]\n"
2762306a36Sopenharmony_ci		"	srl	%[cc],28\n"
2862306a36Sopenharmony_ci		"1:\n"
2962306a36Sopenharmony_ci		EX_TABLE(0b, 1b)
3062306a36Sopenharmony_ci		: [cc] "+&d" (ccode), [addr] "=Q" (*addr)
3162306a36Sopenharmony_ci		: [r1] "d" (r1)
3262306a36Sopenharmony_ci		: "cc", "1");
3362306a36Sopenharmony_ci	return ccode;
3462306a36Sopenharmony_ci}
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ciint stsch(struct subchannel_id schid, struct schib *addr)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	int ccode;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	ccode = __stsch(schid, addr);
4162306a36Sopenharmony_ci	trace_s390_cio_stsch(schid, addr, ccode);
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	return ccode;
4462306a36Sopenharmony_ci}
4562306a36Sopenharmony_ciEXPORT_SYMBOL(stsch);
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistatic inline int __msch(struct subchannel_id schid, struct schib *addr)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	unsigned long r1 = *(unsigned int *)&schid;
5062306a36Sopenharmony_ci	int ccode = -EIO;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	asm volatile(
5362306a36Sopenharmony_ci		"	lgr	1,%[r1]\n"
5462306a36Sopenharmony_ci		"	msch	%[addr]\n"
5562306a36Sopenharmony_ci		"0:	ipm	%[cc]\n"
5662306a36Sopenharmony_ci		"	srl	%[cc],28\n"
5762306a36Sopenharmony_ci		"1:\n"
5862306a36Sopenharmony_ci		EX_TABLE(0b, 1b)
5962306a36Sopenharmony_ci		: [cc] "+&d" (ccode)
6062306a36Sopenharmony_ci		: [r1] "d" (r1), [addr] "Q" (*addr)
6162306a36Sopenharmony_ci		: "cc", "1");
6262306a36Sopenharmony_ci	return ccode;
6362306a36Sopenharmony_ci}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ciint msch(struct subchannel_id schid, struct schib *addr)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	int ccode;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	ccode = __msch(schid, addr);
7062306a36Sopenharmony_ci	trace_s390_cio_msch(schid, addr, ccode);
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	return ccode;
7362306a36Sopenharmony_ci}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistatic inline int __tsch(struct subchannel_id schid, struct irb *addr)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	unsigned long r1 = *(unsigned int *)&schid;
7862306a36Sopenharmony_ci	int ccode;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	asm volatile(
8162306a36Sopenharmony_ci		"	lgr	1,%[r1]\n"
8262306a36Sopenharmony_ci		"	tsch	%[addr]\n"
8362306a36Sopenharmony_ci		"	ipm	%[cc]\n"
8462306a36Sopenharmony_ci		"	srl	%[cc],28"
8562306a36Sopenharmony_ci		: [cc] "=&d" (ccode), [addr] "=Q" (*addr)
8662306a36Sopenharmony_ci		: [r1] "d" (r1)
8762306a36Sopenharmony_ci		: "cc", "1");
8862306a36Sopenharmony_ci	return ccode;
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ciint tsch(struct subchannel_id schid, struct irb *addr)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	int ccode;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	ccode = __tsch(schid, addr);
9662306a36Sopenharmony_ci	trace_s390_cio_tsch(schid, addr, ccode);
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	return ccode;
9962306a36Sopenharmony_ci}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_cistatic inline int __ssch(struct subchannel_id schid, union orb *addr)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	unsigned long r1 = *(unsigned int *)&schid;
10462306a36Sopenharmony_ci	int ccode = -EIO;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	asm volatile(
10762306a36Sopenharmony_ci		"	lgr	1,%[r1]\n"
10862306a36Sopenharmony_ci		"	ssch	%[addr]\n"
10962306a36Sopenharmony_ci		"0:	ipm	%[cc]\n"
11062306a36Sopenharmony_ci		"	srl	%[cc],28\n"
11162306a36Sopenharmony_ci		"1:\n"
11262306a36Sopenharmony_ci		EX_TABLE(0b, 1b)
11362306a36Sopenharmony_ci		: [cc] "+&d" (ccode)
11462306a36Sopenharmony_ci		: [r1] "d" (r1), [addr] "Q" (*addr)
11562306a36Sopenharmony_ci		: "cc", "memory", "1");
11662306a36Sopenharmony_ci	return ccode;
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ciint ssch(struct subchannel_id schid, union orb *addr)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	int ccode;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	ccode = __ssch(schid, addr);
12462306a36Sopenharmony_ci	trace_s390_cio_ssch(schid, addr, ccode);
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	return ccode;
12762306a36Sopenharmony_ci}
12862306a36Sopenharmony_ciEXPORT_SYMBOL(ssch);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic inline int __csch(struct subchannel_id schid)
13162306a36Sopenharmony_ci{
13262306a36Sopenharmony_ci	unsigned long r1 = *(unsigned int *)&schid;
13362306a36Sopenharmony_ci	int ccode;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	asm volatile(
13662306a36Sopenharmony_ci		"	lgr	1,%[r1]\n"
13762306a36Sopenharmony_ci		"	csch\n"
13862306a36Sopenharmony_ci		"	ipm	%[cc]\n"
13962306a36Sopenharmony_ci		"	srl	%[cc],28\n"
14062306a36Sopenharmony_ci		: [cc] "=&d" (ccode)
14162306a36Sopenharmony_ci		: [r1] "d" (r1)
14262306a36Sopenharmony_ci		: "cc", "1");
14362306a36Sopenharmony_ci	return ccode;
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ciint csch(struct subchannel_id schid)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	int ccode;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	ccode = __csch(schid);
15162306a36Sopenharmony_ci	trace_s390_cio_csch(schid, ccode);
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	return ccode;
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ciEXPORT_SYMBOL(csch);
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ciint tpi(struct tpi_info *addr)
15862306a36Sopenharmony_ci{
15962306a36Sopenharmony_ci	int ccode;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	asm volatile(
16262306a36Sopenharmony_ci		"	tpi	%[addr]\n"
16362306a36Sopenharmony_ci		"	ipm	%[cc]\n"
16462306a36Sopenharmony_ci		"	srl	%[cc],28"
16562306a36Sopenharmony_ci		: [cc] "=&d" (ccode), [addr] "=Q" (*addr)
16662306a36Sopenharmony_ci		:
16762306a36Sopenharmony_ci		: "cc");
16862306a36Sopenharmony_ci	trace_s390_cio_tpi(addr, ccode);
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	return ccode;
17162306a36Sopenharmony_ci}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ciint chsc(void *chsc_area)
17462306a36Sopenharmony_ci{
17562306a36Sopenharmony_ci	typedef struct { char _[4096]; } addr_type;
17662306a36Sopenharmony_ci	int cc = -EIO;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	asm volatile(
17962306a36Sopenharmony_ci		"	.insn	rre,0xb25f0000,%[chsc_area],0\n"
18062306a36Sopenharmony_ci		"0:	ipm	%[cc]\n"
18162306a36Sopenharmony_ci		"	srl	%[cc],28\n"
18262306a36Sopenharmony_ci		"1:\n"
18362306a36Sopenharmony_ci		EX_TABLE(0b, 1b)
18462306a36Sopenharmony_ci		: [cc] "+&d" (cc), "+m" (*(addr_type *)chsc_area)
18562306a36Sopenharmony_ci		: [chsc_area] "d" (chsc_area)
18662306a36Sopenharmony_ci		: "cc");
18762306a36Sopenharmony_ci	trace_s390_cio_chsc(chsc_area, cc);
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	return cc;
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ciEXPORT_SYMBOL(chsc);
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_cistatic inline int __rsch(struct subchannel_id schid)
19462306a36Sopenharmony_ci{
19562306a36Sopenharmony_ci	unsigned long r1 = *(unsigned int *)&schid;
19662306a36Sopenharmony_ci	int ccode;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	asm volatile(
19962306a36Sopenharmony_ci		"	lgr	1,%[r1]\n"
20062306a36Sopenharmony_ci		"	rsch\n"
20162306a36Sopenharmony_ci		"	ipm	%[cc]\n"
20262306a36Sopenharmony_ci		"	srl	%[cc],28\n"
20362306a36Sopenharmony_ci		: [cc] "=&d" (ccode)
20462306a36Sopenharmony_ci		: [r1] "d" (r1)
20562306a36Sopenharmony_ci		: "cc", "memory", "1");
20662306a36Sopenharmony_ci	return ccode;
20762306a36Sopenharmony_ci}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ciint rsch(struct subchannel_id schid)
21062306a36Sopenharmony_ci{
21162306a36Sopenharmony_ci	int ccode;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	ccode = __rsch(schid);
21462306a36Sopenharmony_ci	trace_s390_cio_rsch(schid, ccode);
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	return ccode;
21762306a36Sopenharmony_ci}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_cistatic inline int __hsch(struct subchannel_id schid)
22062306a36Sopenharmony_ci{
22162306a36Sopenharmony_ci	unsigned long r1 = *(unsigned int *)&schid;
22262306a36Sopenharmony_ci	int ccode;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	asm volatile(
22562306a36Sopenharmony_ci		"	lgr	1,%[r1]\n"
22662306a36Sopenharmony_ci		"	hsch\n"
22762306a36Sopenharmony_ci		"	ipm	%[cc]\n"
22862306a36Sopenharmony_ci		"	srl	%[cc],28\n"
22962306a36Sopenharmony_ci		: [cc] "=&d" (ccode)
23062306a36Sopenharmony_ci		: [r1] "d" (r1)
23162306a36Sopenharmony_ci		: "cc", "1");
23262306a36Sopenharmony_ci	return ccode;
23362306a36Sopenharmony_ci}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ciint hsch(struct subchannel_id schid)
23662306a36Sopenharmony_ci{
23762306a36Sopenharmony_ci	int ccode;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	ccode = __hsch(schid);
24062306a36Sopenharmony_ci	trace_s390_cio_hsch(schid, ccode);
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	return ccode;
24362306a36Sopenharmony_ci}
24462306a36Sopenharmony_ciEXPORT_SYMBOL(hsch);
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_cistatic inline int __xsch(struct subchannel_id schid)
24762306a36Sopenharmony_ci{
24862306a36Sopenharmony_ci	unsigned long r1 = *(unsigned int *)&schid;
24962306a36Sopenharmony_ci	int ccode;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	asm volatile(
25262306a36Sopenharmony_ci		"	lgr	1,%[r1]\n"
25362306a36Sopenharmony_ci		"	xsch\n"
25462306a36Sopenharmony_ci		"	ipm	%[cc]\n"
25562306a36Sopenharmony_ci		"	srl	%[cc],28\n"
25662306a36Sopenharmony_ci		: [cc] "=&d" (ccode)
25762306a36Sopenharmony_ci		: [r1] "d" (r1)
25862306a36Sopenharmony_ci		: "cc", "1");
25962306a36Sopenharmony_ci	return ccode;
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ciint xsch(struct subchannel_id schid)
26362306a36Sopenharmony_ci{
26462306a36Sopenharmony_ci	int ccode;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	ccode = __xsch(schid);
26762306a36Sopenharmony_ci	trace_s390_cio_xsch(schid, ccode);
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	return ccode;
27062306a36Sopenharmony_ci}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_cistatic inline int __stcrw(struct crw *crw)
27362306a36Sopenharmony_ci{
27462306a36Sopenharmony_ci	int ccode;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	asm volatile(
27762306a36Sopenharmony_ci		"	stcrw	%[crw]\n"
27862306a36Sopenharmony_ci		"	ipm	%[cc]\n"
27962306a36Sopenharmony_ci		"	srl	%[cc],28\n"
28062306a36Sopenharmony_ci		: [cc] "=&d" (ccode), [crw] "=Q" (*crw)
28162306a36Sopenharmony_ci		:
28262306a36Sopenharmony_ci		: "cc");
28362306a36Sopenharmony_ci	return ccode;
28462306a36Sopenharmony_ci}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_cistatic inline int _stcrw(struct crw *crw)
28762306a36Sopenharmony_ci{
28862306a36Sopenharmony_ci#ifdef CONFIG_CIO_INJECT
28962306a36Sopenharmony_ci	if (static_branch_unlikely(&cio_inject_enabled)) {
29062306a36Sopenharmony_ci		if (stcrw_get_injected(crw) == 0)
29162306a36Sopenharmony_ci			return 0;
29262306a36Sopenharmony_ci	}
29362306a36Sopenharmony_ci#endif
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	return __stcrw(crw);
29662306a36Sopenharmony_ci}
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ciint stcrw(struct crw *crw)
29962306a36Sopenharmony_ci{
30062306a36Sopenharmony_ci	int ccode;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	ccode = _stcrw(crw);
30362306a36Sopenharmony_ci	trace_s390_cio_stcrw(crw, ccode);
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	return ccode;
30662306a36Sopenharmony_ci}
307