| 
									
										
										
										
											2013-04-16 14:14:44 +02:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * s390 specific pci instructions | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright IBM Corp. 2013 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <linux/export.h>
 | 
					
						
							|  |  |  | #include <linux/errno.h>
 | 
					
						
							|  |  |  | #include <linux/delay.h>
 | 
					
						
							|  |  |  | #include <asm/pci_insn.h>
 | 
					
						
							| 
									
										
										
										
											2013-04-16 14:16:14 +02:00
										 |  |  | #include <asm/processor.h>
 | 
					
						
							| 
									
										
										
										
											2013-04-16 14:14:44 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | #define ZPCI_INSN_BUSY_DELAY	1	/* 1 microsecond */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Modify PCI Function Controls */ | 
					
						
							|  |  |  | static inline u8 __mpcifc(u64 req, struct zpci_fib *fib, u8 *status) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	u8 cc; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	asm volatile ( | 
					
						
							|  |  |  | 		"	.insn	rxy,0xe300000000d0,%[req],%[fib]\n" | 
					
						
							|  |  |  | 		"	ipm	%[cc]\n" | 
					
						
							|  |  |  | 		"	srl	%[cc],28\n" | 
					
						
							|  |  |  | 		: [cc] "=d" (cc), [req] "+d" (req), [fib] "+Q" (*fib) | 
					
						
							|  |  |  | 		: : "cc"); | 
					
						
							|  |  |  | 	*status = req >> 24 & 0xff; | 
					
						
							|  |  |  | 	return cc; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-25 14:52:23 +02:00
										 |  |  | int zpci_mod_fc(u64 req, struct zpci_fib *fib) | 
					
						
							| 
									
										
										
										
											2013-04-16 14:14:44 +02:00
										 |  |  | { | 
					
						
							|  |  |  | 	u8 cc, status; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	do { | 
					
						
							|  |  |  | 		cc = __mpcifc(req, fib, &status); | 
					
						
							|  |  |  | 		if (cc == 2) | 
					
						
							|  |  |  | 			msleep(ZPCI_INSN_BUSY_DELAY); | 
					
						
							|  |  |  | 	} while (cc == 2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (cc) | 
					
						
							|  |  |  | 		printk_once(KERN_ERR "%s: error cc: %d  status: %d\n", | 
					
						
							|  |  |  | 			     __func__, cc, status); | 
					
						
							|  |  |  | 	return (cc) ? -EIO : 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Refresh PCI Translations */ | 
					
						
							|  |  |  | static inline u8 __rpcit(u64 fn, u64 addr, u64 range, u8 *status) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	register u64 __addr asm("2") = addr; | 
					
						
							|  |  |  | 	register u64 __range asm("3") = range; | 
					
						
							|  |  |  | 	u8 cc; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	asm volatile ( | 
					
						
							|  |  |  | 		"	.insn	rre,0xb9d30000,%[fn],%[addr]\n" | 
					
						
							|  |  |  | 		"	ipm	%[cc]\n" | 
					
						
							|  |  |  | 		"	srl	%[cc],28\n" | 
					
						
							|  |  |  | 		: [cc] "=d" (cc), [fn] "+d" (fn) | 
					
						
							|  |  |  | 		: [addr] "d" (__addr), "d" (__range) | 
					
						
							|  |  |  | 		: "cc"); | 
					
						
							|  |  |  | 	*status = fn >> 24 & 0xff; | 
					
						
							|  |  |  | 	return cc; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-25 14:52:23 +02:00
										 |  |  | int zpci_refresh_trans(u64 fn, u64 addr, u64 range) | 
					
						
							| 
									
										
										
										
											2013-04-16 14:14:44 +02:00
										 |  |  | { | 
					
						
							|  |  |  | 	u8 cc, status; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	do { | 
					
						
							|  |  |  | 		cc = __rpcit(fn, addr, range, &status); | 
					
						
							|  |  |  | 		if (cc == 2) | 
					
						
							|  |  |  | 			udelay(ZPCI_INSN_BUSY_DELAY); | 
					
						
							|  |  |  | 	} while (cc == 2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (cc) | 
					
						
							|  |  |  | 		printk_once(KERN_ERR "%s: error cc: %d  status: %d  dma_addr: %Lx  size: %Lx\n", | 
					
						
							|  |  |  | 			    __func__, cc, status, addr, range); | 
					
						
							|  |  |  | 	return (cc) ? -EIO : 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Set Interruption Controls */ | 
					
						
							| 
									
										
										
										
											2013-06-25 14:52:23 +02:00
										 |  |  | void zpci_set_irq_ctrl(u16 ctl, char *unused, u8 isc) | 
					
						
							| 
									
										
										
										
											2013-04-16 14:14:44 +02:00
										 |  |  | { | 
					
						
							|  |  |  | 	asm volatile ( | 
					
						
							|  |  |  | 		"	.insn	rsy,0xeb00000000d1,%[ctl],%[isc],%[u]\n" | 
					
						
							|  |  |  | 		: : [ctl] "d" (ctl), [isc] "d" (isc << 27), [u] "Q" (*unused)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* PCI Load */ | 
					
						
							| 
									
										
										
										
											2013-04-16 14:16:14 +02:00
										 |  |  | static inline int __pcilg(u64 *data, u64 req, u64 offset, u8 *status) | 
					
						
							| 
									
										
										
										
											2013-04-16 14:14:44 +02:00
										 |  |  | { | 
					
						
							|  |  |  | 	register u64 __req asm("2") = req; | 
					
						
							|  |  |  | 	register u64 __offset asm("3") = offset; | 
					
						
							| 
									
										
										
										
											2013-04-16 14:16:14 +02:00
										 |  |  | 	int cc = -ENXIO; | 
					
						
							| 
									
										
										
										
											2013-04-16 14:14:44 +02:00
										 |  |  | 	u64 __data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	asm volatile ( | 
					
						
							|  |  |  | 		"	.insn	rre,0xb9d20000,%[data],%[req]\n" | 
					
						
							| 
									
										
										
										
											2013-04-16 14:16:14 +02:00
										 |  |  | 		"0:	ipm	%[cc]\n" | 
					
						
							| 
									
										
										
										
											2013-04-16 14:14:44 +02:00
										 |  |  | 		"	srl	%[cc],28\n" | 
					
						
							| 
									
										
										
										
											2013-04-16 14:16:14 +02:00
										 |  |  | 		"1:\n" | 
					
						
							|  |  |  | 		EX_TABLE(0b, 1b) | 
					
						
							|  |  |  | 		: [cc] "+d" (cc), [data] "=d" (__data), [req] "+d" (__req) | 
					
						
							| 
									
										
										
										
											2013-04-16 14:14:44 +02:00
										 |  |  | 		:  "d" (__offset) | 
					
						
							|  |  |  | 		: "cc"); | 
					
						
							|  |  |  | 	*status = __req >> 24 & 0xff; | 
					
						
							| 
									
										
										
										
											2013-04-16 14:17:15 +02:00
										 |  |  | 	if (!cc) | 
					
						
							|  |  |  | 		*data = __data; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-16 14:14:44 +02:00
										 |  |  | 	return cc; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-25 14:52:23 +02:00
										 |  |  | int zpci_load(u64 *data, u64 req, u64 offset) | 
					
						
							| 
									
										
										
										
											2013-04-16 14:14:44 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-04-16 14:16:14 +02:00
										 |  |  | 	u8 status; | 
					
						
							|  |  |  | 	int cc; | 
					
						
							| 
									
										
										
										
											2013-04-16 14:14:44 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	do { | 
					
						
							|  |  |  | 		cc = __pcilg(data, req, offset, &status); | 
					
						
							|  |  |  | 		if (cc == 2) | 
					
						
							|  |  |  | 			udelay(ZPCI_INSN_BUSY_DELAY); | 
					
						
							|  |  |  | 	} while (cc == 2); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-16 14:16:14 +02:00
										 |  |  | 	if (cc) | 
					
						
							| 
									
										
										
										
											2013-04-16 14:14:44 +02:00
										 |  |  | 		printk_once(KERN_ERR "%s: error cc: %d  status: %d  req: %Lx  offset: %Lx\n", | 
					
						
							|  |  |  | 			    __func__, cc, status, req, offset); | 
					
						
							| 
									
										
										
										
											2013-04-16 14:16:14 +02:00
										 |  |  | 	return (cc > 0) ? -EIO : cc; | 
					
						
							| 
									
										
										
										
											2013-04-16 14:14:44 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2013-06-25 14:52:23 +02:00
										 |  |  | EXPORT_SYMBOL_GPL(zpci_load); | 
					
						
							| 
									
										
										
										
											2013-04-16 14:14:44 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* PCI Store */ | 
					
						
							| 
									
										
										
										
											2013-04-16 14:16:14 +02:00
										 |  |  | static inline int __pcistg(u64 data, u64 req, u64 offset, u8 *status) | 
					
						
							| 
									
										
										
										
											2013-04-16 14:14:44 +02:00
										 |  |  | { | 
					
						
							|  |  |  | 	register u64 __req asm("2") = req; | 
					
						
							|  |  |  | 	register u64 __offset asm("3") = offset; | 
					
						
							| 
									
										
										
										
											2013-04-16 14:16:14 +02:00
										 |  |  | 	int cc = -ENXIO; | 
					
						
							| 
									
										
										
										
											2013-04-16 14:14:44 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	asm volatile ( | 
					
						
							|  |  |  | 		"	.insn	rre,0xb9d00000,%[data],%[req]\n" | 
					
						
							| 
									
										
										
										
											2013-04-16 14:16:14 +02:00
										 |  |  | 		"0:	ipm	%[cc]\n" | 
					
						
							| 
									
										
										
										
											2013-04-16 14:14:44 +02:00
										 |  |  | 		"	srl	%[cc],28\n" | 
					
						
							| 
									
										
										
										
											2013-04-16 14:16:14 +02:00
										 |  |  | 		"1:\n" | 
					
						
							|  |  |  | 		EX_TABLE(0b, 1b) | 
					
						
							|  |  |  | 		: [cc] "+d" (cc), [req] "+d" (__req) | 
					
						
							| 
									
										
										
										
											2013-04-16 14:14:44 +02:00
										 |  |  | 		: "d" (__offset), [data] "d" (data) | 
					
						
							|  |  |  | 		: "cc"); | 
					
						
							|  |  |  | 	*status = __req >> 24 & 0xff; | 
					
						
							|  |  |  | 	return cc; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-25 14:52:23 +02:00
										 |  |  | int zpci_store(u64 data, u64 req, u64 offset) | 
					
						
							| 
									
										
										
										
											2013-04-16 14:14:44 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-04-16 14:16:14 +02:00
										 |  |  | 	u8 status; | 
					
						
							|  |  |  | 	int cc; | 
					
						
							| 
									
										
										
										
											2013-04-16 14:14:44 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	do { | 
					
						
							|  |  |  | 		cc = __pcistg(data, req, offset, &status); | 
					
						
							|  |  |  | 		if (cc == 2) | 
					
						
							|  |  |  | 			udelay(ZPCI_INSN_BUSY_DELAY); | 
					
						
							|  |  |  | 	} while (cc == 2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (cc) | 
					
						
							|  |  |  | 		printk_once(KERN_ERR "%s: error cc: %d  status: %d  req: %Lx  offset: %Lx\n", | 
					
						
							|  |  |  | 			__func__, cc, status, req, offset); | 
					
						
							| 
									
										
										
										
											2013-04-16 14:16:14 +02:00
										 |  |  | 	return (cc > 0) ? -EIO : cc; | 
					
						
							| 
									
										
										
										
											2013-04-16 14:14:44 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2013-06-25 14:52:23 +02:00
										 |  |  | EXPORT_SYMBOL_GPL(zpci_store); | 
					
						
							| 
									
										
										
										
											2013-04-16 14:14:44 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* PCI Store Block */ | 
					
						
							| 
									
										
										
										
											2013-04-16 14:16:14 +02:00
										 |  |  | static inline int __pcistb(const u64 *data, u64 req, u64 offset, u8 *status) | 
					
						
							| 
									
										
										
										
											2013-04-16 14:14:44 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-04-16 14:16:14 +02:00
										 |  |  | 	int cc = -ENXIO; | 
					
						
							| 
									
										
										
										
											2013-04-16 14:14:44 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	asm volatile ( | 
					
						
							|  |  |  | 		"	.insn	rsy,0xeb00000000d0,%[req],%[offset],%[data]\n" | 
					
						
							| 
									
										
										
										
											2013-04-16 14:16:14 +02:00
										 |  |  | 		"0:	ipm	%[cc]\n" | 
					
						
							| 
									
										
										
										
											2013-04-16 14:14:44 +02:00
										 |  |  | 		"	srl	%[cc],28\n" | 
					
						
							| 
									
										
										
										
											2013-04-16 14:16:14 +02:00
										 |  |  | 		"1:\n" | 
					
						
							|  |  |  | 		EX_TABLE(0b, 1b) | 
					
						
							|  |  |  | 		: [cc] "+d" (cc), [req] "+d" (req) | 
					
						
							| 
									
										
										
										
											2013-04-16 14:14:44 +02:00
										 |  |  | 		: [offset] "d" (offset), [data] "Q" (*data) | 
					
						
							|  |  |  | 		: "cc"); | 
					
						
							|  |  |  | 	*status = req >> 24 & 0xff; | 
					
						
							|  |  |  | 	return cc; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-25 14:52:23 +02:00
										 |  |  | int zpci_store_block(const u64 *data, u64 req, u64 offset) | 
					
						
							| 
									
										
										
										
											2013-04-16 14:14:44 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-04-16 14:16:14 +02:00
										 |  |  | 	u8 status; | 
					
						
							|  |  |  | 	int cc; | 
					
						
							| 
									
										
										
										
											2013-04-16 14:14:44 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	do { | 
					
						
							|  |  |  | 		cc = __pcistb(data, req, offset, &status); | 
					
						
							|  |  |  | 		if (cc == 2) | 
					
						
							|  |  |  | 			udelay(ZPCI_INSN_BUSY_DELAY); | 
					
						
							|  |  |  | 	} while (cc == 2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (cc) | 
					
						
							|  |  |  | 		printk_once(KERN_ERR "%s: error cc: %d  status: %d  req: %Lx  offset: %Lx\n", | 
					
						
							|  |  |  | 			    __func__, cc, status, req, offset); | 
					
						
							| 
									
										
										
										
											2013-04-16 14:16:14 +02:00
										 |  |  | 	return (cc > 0) ? -EIO : cc; | 
					
						
							| 
									
										
										
										
											2013-04-16 14:14:44 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2013-06-25 14:52:23 +02:00
										 |  |  | EXPORT_SYMBOL_GPL(zpci_store_block); |