xref: /linux/arch/s390/pci/pci_insn.c (revision d66a4c7f760bb13222af9d69a6dca893130d193f)
1adbb3901SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2cbcca5d0SSebastian Ott /*
3cbcca5d0SSebastian Ott  * s390 specific pci instructions
4cbcca5d0SSebastian Ott  *
5cbcca5d0SSebastian Ott  * Copyright IBM Corp. 2013
6cbcca5d0SSebastian Ott  */
7cbcca5d0SSebastian Ott 
8cbcca5d0SSebastian Ott #include <linux/export.h>
9cbcca5d0SSebastian Ott #include <linux/errno.h>
10cbcca5d0SSebastian Ott #include <linux/delay.h>
1171ba41c9SSebastian Ott #include <linux/jump_label.h>
1248070c73SChristian Borntraeger #include <asm/facility.h>
13cbcca5d0SSebastian Ott #include <asm/pci_insn.h>
143d8258e4SSebastian Ott #include <asm/pci_debug.h>
1581deca12SSebastian Ott #include <asm/pci_io.h>
16f0bacb7fSSebastian Ott #include <asm/processor.h>
17cbcca5d0SSebastian Ott 
18cbcca5d0SSebastian Ott #define ZPCI_INSN_BUSY_DELAY	1	/* 1 microsecond */
19cbcca5d0SSebastian Ott 
203d8258e4SSebastian Ott static inline void zpci_err_insn(u8 cc, u8 status, u64 req, u64 offset)
213d8258e4SSebastian Ott {
223d8258e4SSebastian Ott 	struct {
233d8258e4SSebastian Ott 		u64 req;
243d8258e4SSebastian Ott 		u64 offset;
257cc8944eSSebastian Ott 		u8 cc;
267cc8944eSSebastian Ott 		u8 status;
277cc8944eSSebastian Ott 	} __packed data = {req, offset, cc, status};
283d8258e4SSebastian Ott 
293d8258e4SSebastian Ott 	zpci_err_hex(&data, sizeof(data));
303d8258e4SSebastian Ott }
313d8258e4SSebastian Ott 
32cbcca5d0SSebastian Ott /* Modify PCI Function Controls */
33cbcca5d0SSebastian Ott static inline u8 __mpcifc(u64 req, struct zpci_fib *fib, u8 *status)
34cbcca5d0SSebastian Ott {
35cbcca5d0SSebastian Ott 	u8 cc;
36cbcca5d0SSebastian Ott 
37cbcca5d0SSebastian Ott 	asm volatile (
38cbcca5d0SSebastian Ott 		"	.insn	rxy,0xe300000000d0,%[req],%[fib]\n"
39cbcca5d0SSebastian Ott 		"	ipm	%[cc]\n"
40cbcca5d0SSebastian Ott 		"	srl	%[cc],28\n"
41cbcca5d0SSebastian Ott 		: [cc] "=d" (cc), [req] "+d" (req), [fib] "+Q" (*fib)
42cbcca5d0SSebastian Ott 		: : "cc");
43cbcca5d0SSebastian Ott 	*status = req >> 24 & 0xff;
44cbcca5d0SSebastian Ott 	return cc;
45cbcca5d0SSebastian Ott }
46cbcca5d0SSebastian Ott 
474dfbd3efSSebastian Ott u8 zpci_mod_fc(u64 req, struct zpci_fib *fib, u8 *status)
48cbcca5d0SSebastian Ott {
494dfbd3efSSebastian Ott 	u8 cc;
50cbcca5d0SSebastian Ott 
51cbcca5d0SSebastian Ott 	do {
524dfbd3efSSebastian Ott 		cc = __mpcifc(req, fib, status);
53cbcca5d0SSebastian Ott 		if (cc == 2)
54cbcca5d0SSebastian Ott 			msleep(ZPCI_INSN_BUSY_DELAY);
55cbcca5d0SSebastian Ott 	} while (cc == 2);
56cbcca5d0SSebastian Ott 
57cbcca5d0SSebastian Ott 	if (cc)
584dfbd3efSSebastian Ott 		zpci_err_insn(cc, *status, req, 0);
593d8258e4SSebastian Ott 
604dfbd3efSSebastian Ott 	return cc;
61cbcca5d0SSebastian Ott }
62cbcca5d0SSebastian Ott 
63cbcca5d0SSebastian Ott /* Refresh PCI Translations */
64cbcca5d0SSebastian Ott static inline u8 __rpcit(u64 fn, u64 addr, u64 range, u8 *status)
65cbcca5d0SSebastian Ott {
66*d66a4c7fSNiklas Schnelle 	union register_pair addr_range = {.even = addr, .odd = range};
67cbcca5d0SSebastian Ott 	u8 cc;
68cbcca5d0SSebastian Ott 
69cbcca5d0SSebastian Ott 	asm volatile (
70*d66a4c7fSNiklas Schnelle 		"	.insn	rre,0xb9d30000,%[fn],%[addr_range]\n"
71cbcca5d0SSebastian Ott 		"	ipm	%[cc]\n"
72cbcca5d0SSebastian Ott 		"	srl	%[cc],28\n"
73cbcca5d0SSebastian Ott 		: [cc] "=d" (cc), [fn] "+d" (fn)
74*d66a4c7fSNiklas Schnelle 		: [addr_range] "d" (addr_range.pair)
75cbcca5d0SSebastian Ott 		: "cc");
76cbcca5d0SSebastian Ott 	*status = fn >> 24 & 0xff;
77cbcca5d0SSebastian Ott 	return cc;
78cbcca5d0SSebastian Ott }
79cbcca5d0SSebastian Ott 
809389339fSMartin Schwidefsky int zpci_refresh_trans(u64 fn, u64 addr, u64 range)
81cbcca5d0SSebastian Ott {
82cbcca5d0SSebastian Ott 	u8 cc, status;
83cbcca5d0SSebastian Ott 
84cbcca5d0SSebastian Ott 	do {
85cbcca5d0SSebastian Ott 		cc = __rpcit(fn, addr, range, &status);
86cbcca5d0SSebastian Ott 		if (cc == 2)
87cbcca5d0SSebastian Ott 			udelay(ZPCI_INSN_BUSY_DELAY);
88cbcca5d0SSebastian Ott 	} while (cc == 2);
89cbcca5d0SSebastian Ott 
90cbcca5d0SSebastian Ott 	if (cc)
913d8258e4SSebastian Ott 		zpci_err_insn(cc, status, addr, range);
923d8258e4SSebastian Ott 
93a5f10055SSebastian Ott 	if (cc == 1 && (status == 4 || status == 16))
94a5f10055SSebastian Ott 		return -ENOMEM;
95a5f10055SSebastian Ott 
96cbcca5d0SSebastian Ott 	return (cc) ? -EIO : 0;
97cbcca5d0SSebastian Ott }
98cbcca5d0SSebastian Ott 
99cbcca5d0SSebastian Ott /* Set Interruption Controls */
100e979ce7bSSebastian Ott int __zpci_set_irq_ctrl(u16 ctl, u8 isc, union zpci_sic_iib *iib)
101cbcca5d0SSebastian Ott {
10248070c73SChristian Borntraeger 	if (!test_facility(72))
10348070c73SChristian Borntraeger 		return -EIO;
104e979ce7bSSebastian Ott 
105cbcca5d0SSebastian Ott 	asm volatile(
106e979ce7bSSebastian Ott 		".insn	rsy,0xeb00000000d1,%[ctl],%[isc],%[iib]\n"
107e979ce7bSSebastian Ott 		: : [ctl] "d" (ctl), [isc] "d" (isc << 27), [iib] "Q" (*iib));
108e979ce7bSSebastian Ott 
10948070c73SChristian Borntraeger 	return 0;
110cbcca5d0SSebastian Ott }
111cbcca5d0SSebastian Ott 
112cbcca5d0SSebastian Ott /* PCI Load */
1137b411ac6SHeiko Carstens static inline int ____pcilg(u64 *data, u64 req, u64 offset, u8 *status)
114cbcca5d0SSebastian Ott {
115*d66a4c7fSNiklas Schnelle 	union register_pair req_off = {.even = req, .odd = offset};
116f0bacb7fSSebastian Ott 	int cc = -ENXIO;
117cbcca5d0SSebastian Ott 	u64 __data;
118cbcca5d0SSebastian Ott 
119cbcca5d0SSebastian Ott 	asm volatile (
120*d66a4c7fSNiklas Schnelle 		"	.insn	rre,0xb9d20000,%[data],%[req_off]\n"
121f0bacb7fSSebastian Ott 		"0:	ipm	%[cc]\n"
122cbcca5d0SSebastian Ott 		"	srl	%[cc],28\n"
123f0bacb7fSSebastian Ott 		"1:\n"
124f0bacb7fSSebastian Ott 		EX_TABLE(0b, 1b)
125*d66a4c7fSNiklas Schnelle 		: [cc] "+d" (cc), [data] "=d" (__data),
126*d66a4c7fSNiklas Schnelle 		  [req_off] "+&d" (req_off.pair) :: "cc");
127*d66a4c7fSNiklas Schnelle 	*status = req_off.even >> 24 & 0xff;
1287b411ac6SHeiko Carstens 	*data = __data;
1297b411ac6SHeiko Carstens 	return cc;
1307b411ac6SHeiko Carstens }
1317b411ac6SHeiko Carstens 
1327b411ac6SHeiko Carstens static inline int __pcilg(u64 *data, u64 req, u64 offset, u8 *status)
1337b411ac6SHeiko Carstens {
1347b411ac6SHeiko Carstens 	u64 __data;
1357b411ac6SHeiko Carstens 	int cc;
1367b411ac6SHeiko Carstens 
1377b411ac6SHeiko Carstens 	cc = ____pcilg(&__data, req, offset, status);
138b170bad4SSebastian Ott 	if (!cc)
139cbcca5d0SSebastian Ott 		*data = __data;
140b170bad4SSebastian Ott 
141cbcca5d0SSebastian Ott 	return cc;
142cbcca5d0SSebastian Ott }
143cbcca5d0SSebastian Ott 
14481deca12SSebastian Ott int __zpci_load(u64 *data, u64 req, u64 offset)
145cbcca5d0SSebastian Ott {
146f0bacb7fSSebastian Ott 	u8 status;
147f0bacb7fSSebastian Ott 	int cc;
148cbcca5d0SSebastian Ott 
149cbcca5d0SSebastian Ott 	do {
150cbcca5d0SSebastian Ott 		cc = __pcilg(data, req, offset, &status);
151cbcca5d0SSebastian Ott 		if (cc == 2)
152cbcca5d0SSebastian Ott 			udelay(ZPCI_INSN_BUSY_DELAY);
153cbcca5d0SSebastian Ott 	} while (cc == 2);
154cbcca5d0SSebastian Ott 
155f0bacb7fSSebastian Ott 	if (cc)
1563d8258e4SSebastian Ott 		zpci_err_insn(cc, status, req, offset);
1573d8258e4SSebastian Ott 
158f0bacb7fSSebastian Ott 	return (cc > 0) ? -EIO : cc;
159cbcca5d0SSebastian Ott }
16081deca12SSebastian Ott EXPORT_SYMBOL_GPL(__zpci_load);
16181deca12SSebastian Ott 
16271ba41c9SSebastian Ott static inline int zpci_load_fh(u64 *data, const volatile void __iomem *addr,
16371ba41c9SSebastian Ott 			       unsigned long len)
16481deca12SSebastian Ott {
16581deca12SSebastian Ott 	struct zpci_iomap_entry *entry = &zpci_iomap_start[ZPCI_IDX(addr)];
16681deca12SSebastian Ott 	u64 req = ZPCI_CREATE_REQ(entry->fh, entry->bar, len);
16781deca12SSebastian Ott 
16881deca12SSebastian Ott 	return __zpci_load(data, req, ZPCI_OFFSET(addr));
16981deca12SSebastian Ott }
17071ba41c9SSebastian Ott 
17171ba41c9SSebastian Ott static inline int __pcilg_mio(u64 *data, u64 ioaddr, u64 len, u8 *status)
17271ba41c9SSebastian Ott {
173*d66a4c7fSNiklas Schnelle 	union register_pair ioaddr_len = {.even = ioaddr, .odd = len};
17471ba41c9SSebastian Ott 	int cc = -ENXIO;
17571ba41c9SSebastian Ott 	u64 __data;
17671ba41c9SSebastian Ott 
17771ba41c9SSebastian Ott 	asm volatile (
178*d66a4c7fSNiklas Schnelle 		"       .insn   rre,0xb9d60000,%[data],%[ioaddr_len]\n"
17971ba41c9SSebastian Ott 		"0:     ipm     %[cc]\n"
18071ba41c9SSebastian Ott 		"       srl     %[cc],28\n"
18171ba41c9SSebastian Ott 		"1:\n"
18271ba41c9SSebastian Ott 		EX_TABLE(0b, 1b)
183*d66a4c7fSNiklas Schnelle 		: [cc] "+d" (cc), [data] "=d" (__data),
184*d66a4c7fSNiklas Schnelle 		  [ioaddr_len] "+&d" (ioaddr_len.pair) :: "cc");
185*d66a4c7fSNiklas Schnelle 	*status = ioaddr_len.odd >> 24 & 0xff;
18671ba41c9SSebastian Ott 	*data = __data;
18771ba41c9SSebastian Ott 	return cc;
18871ba41c9SSebastian Ott }
18971ba41c9SSebastian Ott 
19071ba41c9SSebastian Ott int zpci_load(u64 *data, const volatile void __iomem *addr, unsigned long len)
19171ba41c9SSebastian Ott {
19271ba41c9SSebastian Ott 	u8 status;
19371ba41c9SSebastian Ott 	int cc;
19471ba41c9SSebastian Ott 
19571ba41c9SSebastian Ott 	if (!static_branch_unlikely(&have_mio))
19671ba41c9SSebastian Ott 		return zpci_load_fh(data, addr, len);
19771ba41c9SSebastian Ott 
19871ba41c9SSebastian Ott 	cc = __pcilg_mio(data, (__force u64) addr, len, &status);
19971ba41c9SSebastian Ott 	if (cc)
20071ba41c9SSebastian Ott 		zpci_err_insn(cc, status, 0, (__force u64) addr);
20171ba41c9SSebastian Ott 
20271ba41c9SSebastian Ott 	return (cc > 0) ? -EIO : cc;
20371ba41c9SSebastian Ott }
2049389339fSMartin Schwidefsky EXPORT_SYMBOL_GPL(zpci_load);
205cbcca5d0SSebastian Ott 
206cbcca5d0SSebastian Ott /* PCI Store */
207f0bacb7fSSebastian Ott static inline int __pcistg(u64 data, u64 req, u64 offset, u8 *status)
208cbcca5d0SSebastian Ott {
209*d66a4c7fSNiklas Schnelle 	union register_pair req_off = {.even = req, .odd = offset};
210f0bacb7fSSebastian Ott 	int cc = -ENXIO;
211cbcca5d0SSebastian Ott 
212cbcca5d0SSebastian Ott 	asm volatile (
213*d66a4c7fSNiklas Schnelle 		"	.insn	rre,0xb9d00000,%[data],%[req_off]\n"
214f0bacb7fSSebastian Ott 		"0:	ipm	%[cc]\n"
215cbcca5d0SSebastian Ott 		"	srl	%[cc],28\n"
216f0bacb7fSSebastian Ott 		"1:\n"
217f0bacb7fSSebastian Ott 		EX_TABLE(0b, 1b)
218*d66a4c7fSNiklas Schnelle 		: [cc] "+d" (cc), [req_off] "+&d" (req_off.pair)
219*d66a4c7fSNiklas Schnelle 		: [data] "d" (data)
220cbcca5d0SSebastian Ott 		: "cc");
221*d66a4c7fSNiklas Schnelle 	*status = req_off.even >> 24 & 0xff;
222cbcca5d0SSebastian Ott 	return cc;
223cbcca5d0SSebastian Ott }
224cbcca5d0SSebastian Ott 
22581deca12SSebastian Ott int __zpci_store(u64 data, u64 req, u64 offset)
226cbcca5d0SSebastian Ott {
227f0bacb7fSSebastian Ott 	u8 status;
228f0bacb7fSSebastian Ott 	int cc;
229cbcca5d0SSebastian Ott 
230cbcca5d0SSebastian Ott 	do {
231cbcca5d0SSebastian Ott 		cc = __pcistg(data, req, offset, &status);
232cbcca5d0SSebastian Ott 		if (cc == 2)
233cbcca5d0SSebastian Ott 			udelay(ZPCI_INSN_BUSY_DELAY);
234cbcca5d0SSebastian Ott 	} while (cc == 2);
235cbcca5d0SSebastian Ott 
236cbcca5d0SSebastian Ott 	if (cc)
2373d8258e4SSebastian Ott 		zpci_err_insn(cc, status, req, offset);
2383d8258e4SSebastian Ott 
239f0bacb7fSSebastian Ott 	return (cc > 0) ? -EIO : cc;
240cbcca5d0SSebastian Ott }
24181deca12SSebastian Ott EXPORT_SYMBOL_GPL(__zpci_store);
24281deca12SSebastian Ott 
24371ba41c9SSebastian Ott static inline int zpci_store_fh(const volatile void __iomem *addr, u64 data,
24471ba41c9SSebastian Ott 				unsigned long len)
24581deca12SSebastian Ott {
24681deca12SSebastian Ott 	struct zpci_iomap_entry *entry = &zpci_iomap_start[ZPCI_IDX(addr)];
24781deca12SSebastian Ott 	u64 req = ZPCI_CREATE_REQ(entry->fh, entry->bar, len);
24881deca12SSebastian Ott 
24981deca12SSebastian Ott 	return __zpci_store(data, req, ZPCI_OFFSET(addr));
25081deca12SSebastian Ott }
25171ba41c9SSebastian Ott 
25271ba41c9SSebastian Ott static inline int __pcistg_mio(u64 data, u64 ioaddr, u64 len, u8 *status)
25371ba41c9SSebastian Ott {
254*d66a4c7fSNiklas Schnelle 	union register_pair ioaddr_len = {.even = ioaddr, .odd = len};
25571ba41c9SSebastian Ott 	int cc = -ENXIO;
25671ba41c9SSebastian Ott 
25771ba41c9SSebastian Ott 	asm volatile (
258*d66a4c7fSNiklas Schnelle 		"       .insn   rre,0xb9d40000,%[data],%[ioaddr_len]\n"
25971ba41c9SSebastian Ott 		"0:     ipm     %[cc]\n"
26071ba41c9SSebastian Ott 		"       srl     %[cc],28\n"
26171ba41c9SSebastian Ott 		"1:\n"
26271ba41c9SSebastian Ott 		EX_TABLE(0b, 1b)
263*d66a4c7fSNiklas Schnelle 		: [cc] "+d" (cc), [ioaddr_len] "+&d" (ioaddr_len.pair)
264*d66a4c7fSNiklas Schnelle 		: [data] "d" (data)
265*d66a4c7fSNiklas Schnelle 		: "cc", "memory");
266*d66a4c7fSNiklas Schnelle 	*status = ioaddr_len.odd >> 24 & 0xff;
26771ba41c9SSebastian Ott 	return cc;
26871ba41c9SSebastian Ott }
26971ba41c9SSebastian Ott 
27071ba41c9SSebastian Ott int zpci_store(const volatile void __iomem *addr, u64 data, unsigned long len)
27171ba41c9SSebastian Ott {
27271ba41c9SSebastian Ott 	u8 status;
27371ba41c9SSebastian Ott 	int cc;
27471ba41c9SSebastian Ott 
27571ba41c9SSebastian Ott 	if (!static_branch_unlikely(&have_mio))
27671ba41c9SSebastian Ott 		return zpci_store_fh(addr, data, len);
27771ba41c9SSebastian Ott 
27871ba41c9SSebastian Ott 	cc = __pcistg_mio(data, (__force u64) addr, len, &status);
27971ba41c9SSebastian Ott 	if (cc)
28071ba41c9SSebastian Ott 		zpci_err_insn(cc, status, 0, (__force u64) addr);
28171ba41c9SSebastian Ott 
28271ba41c9SSebastian Ott 	return (cc > 0) ? -EIO : cc;
28371ba41c9SSebastian Ott }
2849389339fSMartin Schwidefsky EXPORT_SYMBOL_GPL(zpci_store);
285cbcca5d0SSebastian Ott 
286cbcca5d0SSebastian Ott /* PCI Store Block */
287f0bacb7fSSebastian Ott static inline int __pcistb(const u64 *data, u64 req, u64 offset, u8 *status)
288cbcca5d0SSebastian Ott {
289f0bacb7fSSebastian Ott 	int cc = -ENXIO;
290cbcca5d0SSebastian Ott 
291cbcca5d0SSebastian Ott 	asm volatile (
292cbcca5d0SSebastian Ott 		"	.insn	rsy,0xeb00000000d0,%[req],%[offset],%[data]\n"
293f0bacb7fSSebastian Ott 		"0:	ipm	%[cc]\n"
294cbcca5d0SSebastian Ott 		"	srl	%[cc],28\n"
295f0bacb7fSSebastian Ott 		"1:\n"
296f0bacb7fSSebastian Ott 		EX_TABLE(0b, 1b)
297f0bacb7fSSebastian Ott 		: [cc] "+d" (cc), [req] "+d" (req)
298cbcca5d0SSebastian Ott 		: [offset] "d" (offset), [data] "Q" (*data)
299cbcca5d0SSebastian Ott 		: "cc");
300cbcca5d0SSebastian Ott 	*status = req >> 24 & 0xff;
301cbcca5d0SSebastian Ott 	return cc;
302cbcca5d0SSebastian Ott }
303cbcca5d0SSebastian Ott 
30481deca12SSebastian Ott int __zpci_store_block(const u64 *data, u64 req, u64 offset)
305cbcca5d0SSebastian Ott {
306f0bacb7fSSebastian Ott 	u8 status;
307f0bacb7fSSebastian Ott 	int cc;
308cbcca5d0SSebastian Ott 
309cbcca5d0SSebastian Ott 	do {
310cbcca5d0SSebastian Ott 		cc = __pcistb(data, req, offset, &status);
311cbcca5d0SSebastian Ott 		if (cc == 2)
312cbcca5d0SSebastian Ott 			udelay(ZPCI_INSN_BUSY_DELAY);
313cbcca5d0SSebastian Ott 	} while (cc == 2);
314cbcca5d0SSebastian Ott 
315cbcca5d0SSebastian Ott 	if (cc)
3163d8258e4SSebastian Ott 		zpci_err_insn(cc, status, req, offset);
3173d8258e4SSebastian Ott 
318f0bacb7fSSebastian Ott 	return (cc > 0) ? -EIO : cc;
319cbcca5d0SSebastian Ott }
32081deca12SSebastian Ott EXPORT_SYMBOL_GPL(__zpci_store_block);
32181deca12SSebastian Ott 
32271ba41c9SSebastian Ott static inline int zpci_write_block_fh(volatile void __iomem *dst,
32381deca12SSebastian Ott 				      const void *src, unsigned long len)
32481deca12SSebastian Ott {
32581deca12SSebastian Ott 	struct zpci_iomap_entry *entry = &zpci_iomap_start[ZPCI_IDX(dst)];
32681deca12SSebastian Ott 	u64 req = ZPCI_CREATE_REQ(entry->fh, entry->bar, len);
32781deca12SSebastian Ott 	u64 offset = ZPCI_OFFSET(dst);
32881deca12SSebastian Ott 
32981deca12SSebastian Ott 	return __zpci_store_block(src, req, offset);
33081deca12SSebastian Ott }
33171ba41c9SSebastian Ott 
33271ba41c9SSebastian Ott static inline int __pcistb_mio(const u64 *data, u64 ioaddr, u64 len, u8 *status)
33371ba41c9SSebastian Ott {
33471ba41c9SSebastian Ott 	int cc = -ENXIO;
33571ba41c9SSebastian Ott 
33671ba41c9SSebastian Ott 	asm volatile (
33771ba41c9SSebastian Ott 		"       .insn   rsy,0xeb00000000d4,%[len],%[ioaddr],%[data]\n"
33871ba41c9SSebastian Ott 		"0:     ipm     %[cc]\n"
33971ba41c9SSebastian Ott 		"       srl     %[cc],28\n"
34071ba41c9SSebastian Ott 		"1:\n"
34171ba41c9SSebastian Ott 		EX_TABLE(0b, 1b)
34271ba41c9SSebastian Ott 		: [cc] "+d" (cc), [len] "+d" (len)
34371ba41c9SSebastian Ott 		: [ioaddr] "d" (ioaddr), [data] "Q" (*data)
34471ba41c9SSebastian Ott 		: "cc");
34571ba41c9SSebastian Ott 	*status = len >> 24 & 0xff;
34671ba41c9SSebastian Ott 	return cc;
34771ba41c9SSebastian Ott }
34871ba41c9SSebastian Ott 
34971ba41c9SSebastian Ott int zpci_write_block(volatile void __iomem *dst,
35071ba41c9SSebastian Ott 		     const void *src, unsigned long len)
35171ba41c9SSebastian Ott {
35271ba41c9SSebastian Ott 	u8 status;
35371ba41c9SSebastian Ott 	int cc;
35471ba41c9SSebastian Ott 
35571ba41c9SSebastian Ott 	if (!static_branch_unlikely(&have_mio))
35671ba41c9SSebastian Ott 		return zpci_write_block_fh(dst, src, len);
35771ba41c9SSebastian Ott 
35871ba41c9SSebastian Ott 	cc = __pcistb_mio(src, (__force u64) dst, len, &status);
35971ba41c9SSebastian Ott 	if (cc)
36071ba41c9SSebastian Ott 		zpci_err_insn(cc, status, 0, (__force u64) dst);
36171ba41c9SSebastian Ott 
36271ba41c9SSebastian Ott 	return (cc > 0) ? -EIO : cc;
36371ba41c9SSebastian Ott }
36481deca12SSebastian Ott EXPORT_SYMBOL_GPL(zpci_write_block);
36571ba41c9SSebastian Ott 
36671ba41c9SSebastian Ott static inline void __pciwb_mio(void)
36771ba41c9SSebastian Ott {
36871ba41c9SSebastian Ott 	unsigned long unused = 0;
36971ba41c9SSebastian Ott 
37071ba41c9SSebastian Ott 	asm volatile (".insn    rre,0xb9d50000,%[op],%[op]\n"
37171ba41c9SSebastian Ott 		      : [op] "+d" (unused));
37271ba41c9SSebastian Ott }
37371ba41c9SSebastian Ott 
37471ba41c9SSebastian Ott void zpci_barrier(void)
37571ba41c9SSebastian Ott {
37671ba41c9SSebastian Ott 	if (static_branch_likely(&have_mio))
37771ba41c9SSebastian Ott 		__pciwb_mio();
37871ba41c9SSebastian Ott }
37971ba41c9SSebastian Ott EXPORT_SYMBOL_GPL(zpci_barrier);
380