xref: /linux/arch/s390/pci/pci_insn.c (revision 4dfbd3efe3f0cf9ff1325b87491e1b1fe07afaf1)
1cbcca5d0SSebastian Ott /*
2cbcca5d0SSebastian Ott  * s390 specific pci instructions
3cbcca5d0SSebastian Ott  *
4cbcca5d0SSebastian Ott  * Copyright IBM Corp. 2013
5cbcca5d0SSebastian Ott  */
6cbcca5d0SSebastian Ott 
7cbcca5d0SSebastian Ott #include <linux/export.h>
8cbcca5d0SSebastian Ott #include <linux/errno.h>
9cbcca5d0SSebastian Ott #include <linux/delay.h>
10cbcca5d0SSebastian Ott #include <asm/pci_insn.h>
113d8258e4SSebastian Ott #include <asm/pci_debug.h>
12f0bacb7fSSebastian Ott #include <asm/processor.h>
13cbcca5d0SSebastian Ott 
14cbcca5d0SSebastian Ott #define ZPCI_INSN_BUSY_DELAY	1	/* 1 microsecond */
15cbcca5d0SSebastian Ott 
163d8258e4SSebastian Ott static inline void zpci_err_insn(u8 cc, u8 status, u64 req, u64 offset)
173d8258e4SSebastian Ott {
183d8258e4SSebastian Ott 	struct {
193d8258e4SSebastian Ott 		u64 req;
203d8258e4SSebastian Ott 		u64 offset;
217cc8944eSSebastian Ott 		u8 cc;
227cc8944eSSebastian Ott 		u8 status;
237cc8944eSSebastian Ott 	} __packed data = {req, offset, cc, status};
243d8258e4SSebastian Ott 
253d8258e4SSebastian Ott 	zpci_err_hex(&data, sizeof(data));
263d8258e4SSebastian Ott }
273d8258e4SSebastian Ott 
28cbcca5d0SSebastian Ott /* Modify PCI Function Controls */
29cbcca5d0SSebastian Ott static inline u8 __mpcifc(u64 req, struct zpci_fib *fib, u8 *status)
30cbcca5d0SSebastian Ott {
31cbcca5d0SSebastian Ott 	u8 cc;
32cbcca5d0SSebastian Ott 
33cbcca5d0SSebastian Ott 	asm volatile (
34cbcca5d0SSebastian Ott 		"	.insn	rxy,0xe300000000d0,%[req],%[fib]\n"
35cbcca5d0SSebastian Ott 		"	ipm	%[cc]\n"
36cbcca5d0SSebastian Ott 		"	srl	%[cc],28\n"
37cbcca5d0SSebastian Ott 		: [cc] "=d" (cc), [req] "+d" (req), [fib] "+Q" (*fib)
38cbcca5d0SSebastian Ott 		: : "cc");
39cbcca5d0SSebastian Ott 	*status = req >> 24 & 0xff;
40cbcca5d0SSebastian Ott 	return cc;
41cbcca5d0SSebastian Ott }
42cbcca5d0SSebastian Ott 
43*4dfbd3efSSebastian Ott u8 zpci_mod_fc(u64 req, struct zpci_fib *fib, u8 *status)
44cbcca5d0SSebastian Ott {
45*4dfbd3efSSebastian Ott 	u8 cc;
46cbcca5d0SSebastian Ott 
47cbcca5d0SSebastian Ott 	do {
48*4dfbd3efSSebastian Ott 		cc = __mpcifc(req, fib, status);
49cbcca5d0SSebastian Ott 		if (cc == 2)
50cbcca5d0SSebastian Ott 			msleep(ZPCI_INSN_BUSY_DELAY);
51cbcca5d0SSebastian Ott 	} while (cc == 2);
52cbcca5d0SSebastian Ott 
53cbcca5d0SSebastian Ott 	if (cc)
54*4dfbd3efSSebastian Ott 		zpci_err_insn(cc, *status, req, 0);
553d8258e4SSebastian Ott 
56*4dfbd3efSSebastian Ott 	return cc;
57cbcca5d0SSebastian Ott }
58cbcca5d0SSebastian Ott 
59cbcca5d0SSebastian Ott /* Refresh PCI Translations */
60cbcca5d0SSebastian Ott static inline u8 __rpcit(u64 fn, u64 addr, u64 range, u8 *status)
61cbcca5d0SSebastian Ott {
62cbcca5d0SSebastian Ott 	register u64 __addr asm("2") = addr;
63cbcca5d0SSebastian Ott 	register u64 __range asm("3") = range;
64cbcca5d0SSebastian Ott 	u8 cc;
65cbcca5d0SSebastian Ott 
66cbcca5d0SSebastian Ott 	asm volatile (
67cbcca5d0SSebastian Ott 		"	.insn	rre,0xb9d30000,%[fn],%[addr]\n"
68cbcca5d0SSebastian Ott 		"	ipm	%[cc]\n"
69cbcca5d0SSebastian Ott 		"	srl	%[cc],28\n"
70cbcca5d0SSebastian Ott 		: [cc] "=d" (cc), [fn] "+d" (fn)
71cbcca5d0SSebastian Ott 		: [addr] "d" (__addr), "d" (__range)
72cbcca5d0SSebastian Ott 		: "cc");
73cbcca5d0SSebastian Ott 	*status = fn >> 24 & 0xff;
74cbcca5d0SSebastian Ott 	return cc;
75cbcca5d0SSebastian Ott }
76cbcca5d0SSebastian Ott 
779389339fSMartin Schwidefsky int zpci_refresh_trans(u64 fn, u64 addr, u64 range)
78cbcca5d0SSebastian Ott {
79cbcca5d0SSebastian Ott 	u8 cc, status;
80cbcca5d0SSebastian Ott 
81cbcca5d0SSebastian Ott 	do {
82cbcca5d0SSebastian Ott 		cc = __rpcit(fn, addr, range, &status);
83cbcca5d0SSebastian Ott 		if (cc == 2)
84cbcca5d0SSebastian Ott 			udelay(ZPCI_INSN_BUSY_DELAY);
85cbcca5d0SSebastian Ott 	} while (cc == 2);
86cbcca5d0SSebastian Ott 
87cbcca5d0SSebastian Ott 	if (cc)
883d8258e4SSebastian Ott 		zpci_err_insn(cc, status, addr, range);
893d8258e4SSebastian Ott 
90cbcca5d0SSebastian Ott 	return (cc) ? -EIO : 0;
91cbcca5d0SSebastian Ott }
92cbcca5d0SSebastian Ott 
93cbcca5d0SSebastian Ott /* Set Interruption Controls */
949389339fSMartin Schwidefsky void zpci_set_irq_ctrl(u16 ctl, char *unused, u8 isc)
95cbcca5d0SSebastian Ott {
96cbcca5d0SSebastian Ott 	asm volatile (
97cbcca5d0SSebastian Ott 		"	.insn	rsy,0xeb00000000d1,%[ctl],%[isc],%[u]\n"
98cbcca5d0SSebastian Ott 		: : [ctl] "d" (ctl), [isc] "d" (isc << 27), [u] "Q" (*unused));
99cbcca5d0SSebastian Ott }
100cbcca5d0SSebastian Ott 
101cbcca5d0SSebastian Ott /* PCI Load */
1027b411ac6SHeiko Carstens static inline int ____pcilg(u64 *data, u64 req, u64 offset, u8 *status)
103cbcca5d0SSebastian Ott {
104cbcca5d0SSebastian Ott 	register u64 __req asm("2") = req;
105cbcca5d0SSebastian Ott 	register u64 __offset asm("3") = offset;
106f0bacb7fSSebastian Ott 	int cc = -ENXIO;
107cbcca5d0SSebastian Ott 	u64 __data;
108cbcca5d0SSebastian Ott 
109cbcca5d0SSebastian Ott 	asm volatile (
110cbcca5d0SSebastian Ott 		"	.insn	rre,0xb9d20000,%[data],%[req]\n"
111f0bacb7fSSebastian Ott 		"0:	ipm	%[cc]\n"
112cbcca5d0SSebastian Ott 		"	srl	%[cc],28\n"
113f0bacb7fSSebastian Ott 		"1:\n"
114f0bacb7fSSebastian Ott 		EX_TABLE(0b, 1b)
115f0bacb7fSSebastian Ott 		: [cc] "+d" (cc), [data] "=d" (__data), [req] "+d" (__req)
116cbcca5d0SSebastian Ott 		:  "d" (__offset)
117cbcca5d0SSebastian Ott 		: "cc");
118cbcca5d0SSebastian Ott 	*status = __req >> 24 & 0xff;
1197b411ac6SHeiko Carstens 	*data = __data;
1207b411ac6SHeiko Carstens 	return cc;
1217b411ac6SHeiko Carstens }
1227b411ac6SHeiko Carstens 
1237b411ac6SHeiko Carstens static inline int __pcilg(u64 *data, u64 req, u64 offset, u8 *status)
1247b411ac6SHeiko Carstens {
1257b411ac6SHeiko Carstens 	u64 __data;
1267b411ac6SHeiko Carstens 	int cc;
1277b411ac6SHeiko Carstens 
1287b411ac6SHeiko Carstens 	cc = ____pcilg(&__data, req, offset, status);
129b170bad4SSebastian Ott 	if (!cc)
130cbcca5d0SSebastian Ott 		*data = __data;
131b170bad4SSebastian Ott 
132cbcca5d0SSebastian Ott 	return cc;
133cbcca5d0SSebastian Ott }
134cbcca5d0SSebastian Ott 
1359389339fSMartin Schwidefsky int zpci_load(u64 *data, u64 req, u64 offset)
136cbcca5d0SSebastian Ott {
137f0bacb7fSSebastian Ott 	u8 status;
138f0bacb7fSSebastian Ott 	int cc;
139cbcca5d0SSebastian Ott 
140cbcca5d0SSebastian Ott 	do {
141cbcca5d0SSebastian Ott 		cc = __pcilg(data, req, offset, &status);
142cbcca5d0SSebastian Ott 		if (cc == 2)
143cbcca5d0SSebastian Ott 			udelay(ZPCI_INSN_BUSY_DELAY);
144cbcca5d0SSebastian Ott 	} while (cc == 2);
145cbcca5d0SSebastian Ott 
146f0bacb7fSSebastian Ott 	if (cc)
1473d8258e4SSebastian Ott 		zpci_err_insn(cc, status, req, offset);
1483d8258e4SSebastian Ott 
149f0bacb7fSSebastian Ott 	return (cc > 0) ? -EIO : cc;
150cbcca5d0SSebastian Ott }
1519389339fSMartin Schwidefsky EXPORT_SYMBOL_GPL(zpci_load);
152cbcca5d0SSebastian Ott 
153cbcca5d0SSebastian Ott /* PCI Store */
154f0bacb7fSSebastian Ott static inline int __pcistg(u64 data, u64 req, u64 offset, u8 *status)
155cbcca5d0SSebastian Ott {
156cbcca5d0SSebastian Ott 	register u64 __req asm("2") = req;
157cbcca5d0SSebastian Ott 	register u64 __offset asm("3") = offset;
158f0bacb7fSSebastian Ott 	int cc = -ENXIO;
159cbcca5d0SSebastian Ott 
160cbcca5d0SSebastian Ott 	asm volatile (
161cbcca5d0SSebastian Ott 		"	.insn	rre,0xb9d00000,%[data],%[req]\n"
162f0bacb7fSSebastian Ott 		"0:	ipm	%[cc]\n"
163cbcca5d0SSebastian Ott 		"	srl	%[cc],28\n"
164f0bacb7fSSebastian Ott 		"1:\n"
165f0bacb7fSSebastian Ott 		EX_TABLE(0b, 1b)
166f0bacb7fSSebastian Ott 		: [cc] "+d" (cc), [req] "+d" (__req)
167cbcca5d0SSebastian Ott 		: "d" (__offset), [data] "d" (data)
168cbcca5d0SSebastian Ott 		: "cc");
169cbcca5d0SSebastian Ott 	*status = __req >> 24 & 0xff;
170cbcca5d0SSebastian Ott 	return cc;
171cbcca5d0SSebastian Ott }
172cbcca5d0SSebastian Ott 
1739389339fSMartin Schwidefsky int zpci_store(u64 data, u64 req, u64 offset)
174cbcca5d0SSebastian Ott {
175f0bacb7fSSebastian Ott 	u8 status;
176f0bacb7fSSebastian Ott 	int cc;
177cbcca5d0SSebastian Ott 
178cbcca5d0SSebastian Ott 	do {
179cbcca5d0SSebastian Ott 		cc = __pcistg(data, req, offset, &status);
180cbcca5d0SSebastian Ott 		if (cc == 2)
181cbcca5d0SSebastian Ott 			udelay(ZPCI_INSN_BUSY_DELAY);
182cbcca5d0SSebastian Ott 	} while (cc == 2);
183cbcca5d0SSebastian Ott 
184cbcca5d0SSebastian Ott 	if (cc)
1853d8258e4SSebastian Ott 		zpci_err_insn(cc, status, req, offset);
1863d8258e4SSebastian Ott 
187f0bacb7fSSebastian Ott 	return (cc > 0) ? -EIO : cc;
188cbcca5d0SSebastian Ott }
1899389339fSMartin Schwidefsky EXPORT_SYMBOL_GPL(zpci_store);
190cbcca5d0SSebastian Ott 
191cbcca5d0SSebastian Ott /* PCI Store Block */
192f0bacb7fSSebastian Ott static inline int __pcistb(const u64 *data, u64 req, u64 offset, u8 *status)
193cbcca5d0SSebastian Ott {
194f0bacb7fSSebastian Ott 	int cc = -ENXIO;
195cbcca5d0SSebastian Ott 
196cbcca5d0SSebastian Ott 	asm volatile (
197cbcca5d0SSebastian Ott 		"	.insn	rsy,0xeb00000000d0,%[req],%[offset],%[data]\n"
198f0bacb7fSSebastian Ott 		"0:	ipm	%[cc]\n"
199cbcca5d0SSebastian Ott 		"	srl	%[cc],28\n"
200f0bacb7fSSebastian Ott 		"1:\n"
201f0bacb7fSSebastian Ott 		EX_TABLE(0b, 1b)
202f0bacb7fSSebastian Ott 		: [cc] "+d" (cc), [req] "+d" (req)
203cbcca5d0SSebastian Ott 		: [offset] "d" (offset), [data] "Q" (*data)
204cbcca5d0SSebastian Ott 		: "cc");
205cbcca5d0SSebastian Ott 	*status = req >> 24 & 0xff;
206cbcca5d0SSebastian Ott 	return cc;
207cbcca5d0SSebastian Ott }
208cbcca5d0SSebastian Ott 
2099389339fSMartin Schwidefsky int zpci_store_block(const u64 *data, u64 req, u64 offset)
210cbcca5d0SSebastian Ott {
211f0bacb7fSSebastian Ott 	u8 status;
212f0bacb7fSSebastian Ott 	int cc;
213cbcca5d0SSebastian Ott 
214cbcca5d0SSebastian Ott 	do {
215cbcca5d0SSebastian Ott 		cc = __pcistb(data, req, offset, &status);
216cbcca5d0SSebastian Ott 		if (cc == 2)
217cbcca5d0SSebastian Ott 			udelay(ZPCI_INSN_BUSY_DELAY);
218cbcca5d0SSebastian Ott 	} while (cc == 2);
219cbcca5d0SSebastian Ott 
220cbcca5d0SSebastian Ott 	if (cc)
2213d8258e4SSebastian Ott 		zpci_err_insn(cc, status, req, offset);
2223d8258e4SSebastian Ott 
223f0bacb7fSSebastian Ott 	return (cc > 0) ? -EIO : cc;
224cbcca5d0SSebastian Ott }
2259389339fSMartin Schwidefsky EXPORT_SYMBOL_GPL(zpci_store_block);
226