18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * s390 specific pci instructions
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright IBM Corp. 2013
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/export.h>
98c2ecf20Sopenharmony_ci#include <linux/errno.h>
108c2ecf20Sopenharmony_ci#include <linux/delay.h>
118c2ecf20Sopenharmony_ci#include <linux/jump_label.h>
128c2ecf20Sopenharmony_ci#include <asm/facility.h>
138c2ecf20Sopenharmony_ci#include <asm/pci_insn.h>
148c2ecf20Sopenharmony_ci#include <asm/pci_debug.h>
158c2ecf20Sopenharmony_ci#include <asm/pci_io.h>
168c2ecf20Sopenharmony_ci#include <asm/processor.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#define ZPCI_INSN_BUSY_DELAY	1	/* 1 microsecond */
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistatic inline void zpci_err_insn(u8 cc, u8 status, u64 req, u64 offset)
218c2ecf20Sopenharmony_ci{
228c2ecf20Sopenharmony_ci	struct {
238c2ecf20Sopenharmony_ci		u64 req;
248c2ecf20Sopenharmony_ci		u64 offset;
258c2ecf20Sopenharmony_ci		u8 cc;
268c2ecf20Sopenharmony_ci		u8 status;
278c2ecf20Sopenharmony_ci	} __packed data = {req, offset, cc, status};
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	zpci_err_hex(&data, sizeof(data));
308c2ecf20Sopenharmony_ci}
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci/* Modify PCI Function Controls */
338c2ecf20Sopenharmony_cistatic inline u8 __mpcifc(u64 req, struct zpci_fib *fib, u8 *status)
348c2ecf20Sopenharmony_ci{
358c2ecf20Sopenharmony_ci	u8 cc;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	asm volatile (
388c2ecf20Sopenharmony_ci		"	.insn	rxy,0xe300000000d0,%[req],%[fib]\n"
398c2ecf20Sopenharmony_ci		"	ipm	%[cc]\n"
408c2ecf20Sopenharmony_ci		"	srl	%[cc],28\n"
418c2ecf20Sopenharmony_ci		: [cc] "=d" (cc), [req] "+d" (req), [fib] "+Q" (*fib)
428c2ecf20Sopenharmony_ci		: : "cc");
438c2ecf20Sopenharmony_ci	*status = req >> 24 & 0xff;
448c2ecf20Sopenharmony_ci	return cc;
458c2ecf20Sopenharmony_ci}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ciu8 zpci_mod_fc(u64 req, struct zpci_fib *fib, u8 *status)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	u8 cc;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	do {
528c2ecf20Sopenharmony_ci		cc = __mpcifc(req, fib, status);
538c2ecf20Sopenharmony_ci		if (cc == 2)
548c2ecf20Sopenharmony_ci			msleep(ZPCI_INSN_BUSY_DELAY);
558c2ecf20Sopenharmony_ci	} while (cc == 2);
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	if (cc)
588c2ecf20Sopenharmony_ci		zpci_err_insn(cc, *status, req, 0);
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	return cc;
618c2ecf20Sopenharmony_ci}
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci/* Refresh PCI Translations */
648c2ecf20Sopenharmony_cistatic inline u8 __rpcit(u64 fn, u64 addr, u64 range, u8 *status)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	register u64 __addr asm("2") = addr;
678c2ecf20Sopenharmony_ci	register u64 __range asm("3") = range;
688c2ecf20Sopenharmony_ci	u8 cc;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	asm volatile (
718c2ecf20Sopenharmony_ci		"	.insn	rre,0xb9d30000,%[fn],%[addr]\n"
728c2ecf20Sopenharmony_ci		"	ipm	%[cc]\n"
738c2ecf20Sopenharmony_ci		"	srl	%[cc],28\n"
748c2ecf20Sopenharmony_ci		: [cc] "=d" (cc), [fn] "+d" (fn)
758c2ecf20Sopenharmony_ci		: [addr] "d" (__addr), "d" (__range)
768c2ecf20Sopenharmony_ci		: "cc");
778c2ecf20Sopenharmony_ci	*status = fn >> 24 & 0xff;
788c2ecf20Sopenharmony_ci	return cc;
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ciint zpci_refresh_trans(u64 fn, u64 addr, u64 range)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	u8 cc, status;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	do {
868c2ecf20Sopenharmony_ci		cc = __rpcit(fn, addr, range, &status);
878c2ecf20Sopenharmony_ci		if (cc == 2)
888c2ecf20Sopenharmony_ci			udelay(ZPCI_INSN_BUSY_DELAY);
898c2ecf20Sopenharmony_ci	} while (cc == 2);
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	if (cc)
928c2ecf20Sopenharmony_ci		zpci_err_insn(cc, status, addr, range);
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	if (cc == 1 && (status == 4 || status == 16))
958c2ecf20Sopenharmony_ci		return -ENOMEM;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	return (cc) ? -EIO : 0;
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci/* Set Interruption Controls */
1018c2ecf20Sopenharmony_ciint __zpci_set_irq_ctrl(u16 ctl, u8 isc, union zpci_sic_iib *iib)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	if (!test_facility(72))
1048c2ecf20Sopenharmony_ci		return -EIO;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	asm volatile(
1078c2ecf20Sopenharmony_ci		".insn	rsy,0xeb00000000d1,%[ctl],%[isc],%[iib]\n"
1088c2ecf20Sopenharmony_ci		: : [ctl] "d" (ctl), [isc] "d" (isc << 27), [iib] "Q" (*iib));
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	return 0;
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci/* PCI Load */
1148c2ecf20Sopenharmony_cistatic inline int ____pcilg(u64 *data, u64 req, u64 offset, u8 *status)
1158c2ecf20Sopenharmony_ci{
1168c2ecf20Sopenharmony_ci	register u64 __req asm("2") = req;
1178c2ecf20Sopenharmony_ci	register u64 __offset asm("3") = offset;
1188c2ecf20Sopenharmony_ci	int cc = -ENXIO;
1198c2ecf20Sopenharmony_ci	u64 __data;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	asm volatile (
1228c2ecf20Sopenharmony_ci		"	.insn	rre,0xb9d20000,%[data],%[req]\n"
1238c2ecf20Sopenharmony_ci		"0:	ipm	%[cc]\n"
1248c2ecf20Sopenharmony_ci		"	srl	%[cc],28\n"
1258c2ecf20Sopenharmony_ci		"1:\n"
1268c2ecf20Sopenharmony_ci		EX_TABLE(0b, 1b)
1278c2ecf20Sopenharmony_ci		: [cc] "+d" (cc), [data] "=d" (__data), [req] "+d" (__req)
1288c2ecf20Sopenharmony_ci		:  "d" (__offset)
1298c2ecf20Sopenharmony_ci		: "cc");
1308c2ecf20Sopenharmony_ci	*status = __req >> 24 & 0xff;
1318c2ecf20Sopenharmony_ci	*data = __data;
1328c2ecf20Sopenharmony_ci	return cc;
1338c2ecf20Sopenharmony_ci}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_cistatic inline int __pcilg(u64 *data, u64 req, u64 offset, u8 *status)
1368c2ecf20Sopenharmony_ci{
1378c2ecf20Sopenharmony_ci	u64 __data;
1388c2ecf20Sopenharmony_ci	int cc;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	cc = ____pcilg(&__data, req, offset, status);
1418c2ecf20Sopenharmony_ci	if (!cc)
1428c2ecf20Sopenharmony_ci		*data = __data;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	return cc;
1458c2ecf20Sopenharmony_ci}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ciint __zpci_load(u64 *data, u64 req, u64 offset)
1488c2ecf20Sopenharmony_ci{
1498c2ecf20Sopenharmony_ci	u8 status;
1508c2ecf20Sopenharmony_ci	int cc;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	do {
1538c2ecf20Sopenharmony_ci		cc = __pcilg(data, req, offset, &status);
1548c2ecf20Sopenharmony_ci		if (cc == 2)
1558c2ecf20Sopenharmony_ci			udelay(ZPCI_INSN_BUSY_DELAY);
1568c2ecf20Sopenharmony_ci	} while (cc == 2);
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	if (cc)
1598c2ecf20Sopenharmony_ci		zpci_err_insn(cc, status, req, offset);
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	return (cc > 0) ? -EIO : cc;
1628c2ecf20Sopenharmony_ci}
1638c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__zpci_load);
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_cistatic inline int zpci_load_fh(u64 *data, const volatile void __iomem *addr,
1668c2ecf20Sopenharmony_ci			       unsigned long len)
1678c2ecf20Sopenharmony_ci{
1688c2ecf20Sopenharmony_ci	struct zpci_iomap_entry *entry = &zpci_iomap_start[ZPCI_IDX(addr)];
1698c2ecf20Sopenharmony_ci	u64 req = ZPCI_CREATE_REQ(entry->fh, entry->bar, len);
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	return __zpci_load(data, req, ZPCI_OFFSET(addr));
1728c2ecf20Sopenharmony_ci}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_cistatic inline int __pcilg_mio(u64 *data, u64 ioaddr, u64 len, u8 *status)
1758c2ecf20Sopenharmony_ci{
1768c2ecf20Sopenharmony_ci	register u64 addr asm("2") = ioaddr;
1778c2ecf20Sopenharmony_ci	register u64 r3 asm("3") = len;
1788c2ecf20Sopenharmony_ci	int cc = -ENXIO;
1798c2ecf20Sopenharmony_ci	u64 __data;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	asm volatile (
1828c2ecf20Sopenharmony_ci		"       .insn   rre,0xb9d60000,%[data],%[ioaddr]\n"
1838c2ecf20Sopenharmony_ci		"0:     ipm     %[cc]\n"
1848c2ecf20Sopenharmony_ci		"       srl     %[cc],28\n"
1858c2ecf20Sopenharmony_ci		"1:\n"
1868c2ecf20Sopenharmony_ci		EX_TABLE(0b, 1b)
1878c2ecf20Sopenharmony_ci		: [cc] "+d" (cc), [data] "=d" (__data), "+d" (r3)
1888c2ecf20Sopenharmony_ci		: [ioaddr] "d" (addr)
1898c2ecf20Sopenharmony_ci		: "cc");
1908c2ecf20Sopenharmony_ci	*status = r3 >> 24 & 0xff;
1918c2ecf20Sopenharmony_ci	*data = __data;
1928c2ecf20Sopenharmony_ci	return cc;
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ciint zpci_load(u64 *data, const volatile void __iomem *addr, unsigned long len)
1968c2ecf20Sopenharmony_ci{
1978c2ecf20Sopenharmony_ci	u8 status;
1988c2ecf20Sopenharmony_ci	int cc;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	if (!static_branch_unlikely(&have_mio))
2018c2ecf20Sopenharmony_ci		return zpci_load_fh(data, addr, len);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	cc = __pcilg_mio(data, (__force u64) addr, len, &status);
2048c2ecf20Sopenharmony_ci	if (cc)
2058c2ecf20Sopenharmony_ci		zpci_err_insn(cc, status, 0, (__force u64) addr);
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	return (cc > 0) ? -EIO : cc;
2088c2ecf20Sopenharmony_ci}
2098c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(zpci_load);
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci/* PCI Store */
2128c2ecf20Sopenharmony_cistatic inline int __pcistg(u64 data, u64 req, u64 offset, u8 *status)
2138c2ecf20Sopenharmony_ci{
2148c2ecf20Sopenharmony_ci	register u64 __req asm("2") = req;
2158c2ecf20Sopenharmony_ci	register u64 __offset asm("3") = offset;
2168c2ecf20Sopenharmony_ci	int cc = -ENXIO;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	asm volatile (
2198c2ecf20Sopenharmony_ci		"	.insn	rre,0xb9d00000,%[data],%[req]\n"
2208c2ecf20Sopenharmony_ci		"0:	ipm	%[cc]\n"
2218c2ecf20Sopenharmony_ci		"	srl	%[cc],28\n"
2228c2ecf20Sopenharmony_ci		"1:\n"
2238c2ecf20Sopenharmony_ci		EX_TABLE(0b, 1b)
2248c2ecf20Sopenharmony_ci		: [cc] "+d" (cc), [req] "+d" (__req)
2258c2ecf20Sopenharmony_ci		: "d" (__offset), [data] "d" (data)
2268c2ecf20Sopenharmony_ci		: "cc");
2278c2ecf20Sopenharmony_ci	*status = __req >> 24 & 0xff;
2288c2ecf20Sopenharmony_ci	return cc;
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ciint __zpci_store(u64 data, u64 req, u64 offset)
2328c2ecf20Sopenharmony_ci{
2338c2ecf20Sopenharmony_ci	u8 status;
2348c2ecf20Sopenharmony_ci	int cc;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	do {
2378c2ecf20Sopenharmony_ci		cc = __pcistg(data, req, offset, &status);
2388c2ecf20Sopenharmony_ci		if (cc == 2)
2398c2ecf20Sopenharmony_ci			udelay(ZPCI_INSN_BUSY_DELAY);
2408c2ecf20Sopenharmony_ci	} while (cc == 2);
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	if (cc)
2438c2ecf20Sopenharmony_ci		zpci_err_insn(cc, status, req, offset);
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	return (cc > 0) ? -EIO : cc;
2468c2ecf20Sopenharmony_ci}
2478c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__zpci_store);
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_cistatic inline int zpci_store_fh(const volatile void __iomem *addr, u64 data,
2508c2ecf20Sopenharmony_ci				unsigned long len)
2518c2ecf20Sopenharmony_ci{
2528c2ecf20Sopenharmony_ci	struct zpci_iomap_entry *entry = &zpci_iomap_start[ZPCI_IDX(addr)];
2538c2ecf20Sopenharmony_ci	u64 req = ZPCI_CREATE_REQ(entry->fh, entry->bar, len);
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	return __zpci_store(data, req, ZPCI_OFFSET(addr));
2568c2ecf20Sopenharmony_ci}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_cistatic inline int __pcistg_mio(u64 data, u64 ioaddr, u64 len, u8 *status)
2598c2ecf20Sopenharmony_ci{
2608c2ecf20Sopenharmony_ci	register u64 addr asm("2") = ioaddr;
2618c2ecf20Sopenharmony_ci	register u64 r3 asm("3") = len;
2628c2ecf20Sopenharmony_ci	int cc = -ENXIO;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	asm volatile (
2658c2ecf20Sopenharmony_ci		"       .insn   rre,0xb9d40000,%[data],%[ioaddr]\n"
2668c2ecf20Sopenharmony_ci		"0:     ipm     %[cc]\n"
2678c2ecf20Sopenharmony_ci		"       srl     %[cc],28\n"
2688c2ecf20Sopenharmony_ci		"1:\n"
2698c2ecf20Sopenharmony_ci		EX_TABLE(0b, 1b)
2708c2ecf20Sopenharmony_ci		: [cc] "+d" (cc), "+d" (r3)
2718c2ecf20Sopenharmony_ci		: [data] "d" (data), [ioaddr] "d" (addr)
2728c2ecf20Sopenharmony_ci		: "cc");
2738c2ecf20Sopenharmony_ci	*status = r3 >> 24 & 0xff;
2748c2ecf20Sopenharmony_ci	return cc;
2758c2ecf20Sopenharmony_ci}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ciint zpci_store(const volatile void __iomem *addr, u64 data, unsigned long len)
2788c2ecf20Sopenharmony_ci{
2798c2ecf20Sopenharmony_ci	u8 status;
2808c2ecf20Sopenharmony_ci	int cc;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	if (!static_branch_unlikely(&have_mio))
2838c2ecf20Sopenharmony_ci		return zpci_store_fh(addr, data, len);
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	cc = __pcistg_mio(data, (__force u64) addr, len, &status);
2868c2ecf20Sopenharmony_ci	if (cc)
2878c2ecf20Sopenharmony_ci		zpci_err_insn(cc, status, 0, (__force u64) addr);
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	return (cc > 0) ? -EIO : cc;
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(zpci_store);
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci/* PCI Store Block */
2948c2ecf20Sopenharmony_cistatic inline int __pcistb(const u64 *data, u64 req, u64 offset, u8 *status)
2958c2ecf20Sopenharmony_ci{
2968c2ecf20Sopenharmony_ci	int cc = -ENXIO;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	asm volatile (
2998c2ecf20Sopenharmony_ci		"	.insn	rsy,0xeb00000000d0,%[req],%[offset],%[data]\n"
3008c2ecf20Sopenharmony_ci		"0:	ipm	%[cc]\n"
3018c2ecf20Sopenharmony_ci		"	srl	%[cc],28\n"
3028c2ecf20Sopenharmony_ci		"1:\n"
3038c2ecf20Sopenharmony_ci		EX_TABLE(0b, 1b)
3048c2ecf20Sopenharmony_ci		: [cc] "+d" (cc), [req] "+d" (req)
3058c2ecf20Sopenharmony_ci		: [offset] "d" (offset), [data] "Q" (*data)
3068c2ecf20Sopenharmony_ci		: "cc");
3078c2ecf20Sopenharmony_ci	*status = req >> 24 & 0xff;
3088c2ecf20Sopenharmony_ci	return cc;
3098c2ecf20Sopenharmony_ci}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ciint __zpci_store_block(const u64 *data, u64 req, u64 offset)
3128c2ecf20Sopenharmony_ci{
3138c2ecf20Sopenharmony_ci	u8 status;
3148c2ecf20Sopenharmony_ci	int cc;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	do {
3178c2ecf20Sopenharmony_ci		cc = __pcistb(data, req, offset, &status);
3188c2ecf20Sopenharmony_ci		if (cc == 2)
3198c2ecf20Sopenharmony_ci			udelay(ZPCI_INSN_BUSY_DELAY);
3208c2ecf20Sopenharmony_ci	} while (cc == 2);
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	if (cc)
3238c2ecf20Sopenharmony_ci		zpci_err_insn(cc, status, req, offset);
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	return (cc > 0) ? -EIO : cc;
3268c2ecf20Sopenharmony_ci}
3278c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__zpci_store_block);
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_cistatic inline int zpci_write_block_fh(volatile void __iomem *dst,
3308c2ecf20Sopenharmony_ci				      const void *src, unsigned long len)
3318c2ecf20Sopenharmony_ci{
3328c2ecf20Sopenharmony_ci	struct zpci_iomap_entry *entry = &zpci_iomap_start[ZPCI_IDX(dst)];
3338c2ecf20Sopenharmony_ci	u64 req = ZPCI_CREATE_REQ(entry->fh, entry->bar, len);
3348c2ecf20Sopenharmony_ci	u64 offset = ZPCI_OFFSET(dst);
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	return __zpci_store_block(src, req, offset);
3378c2ecf20Sopenharmony_ci}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_cistatic inline int __pcistb_mio(const u64 *data, u64 ioaddr, u64 len, u8 *status)
3408c2ecf20Sopenharmony_ci{
3418c2ecf20Sopenharmony_ci	int cc = -ENXIO;
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	asm volatile (
3448c2ecf20Sopenharmony_ci		"       .insn   rsy,0xeb00000000d4,%[len],%[ioaddr],%[data]\n"
3458c2ecf20Sopenharmony_ci		"0:     ipm     %[cc]\n"
3468c2ecf20Sopenharmony_ci		"       srl     %[cc],28\n"
3478c2ecf20Sopenharmony_ci		"1:\n"
3488c2ecf20Sopenharmony_ci		EX_TABLE(0b, 1b)
3498c2ecf20Sopenharmony_ci		: [cc] "+d" (cc), [len] "+d" (len)
3508c2ecf20Sopenharmony_ci		: [ioaddr] "d" (ioaddr), [data] "Q" (*data)
3518c2ecf20Sopenharmony_ci		: "cc");
3528c2ecf20Sopenharmony_ci	*status = len >> 24 & 0xff;
3538c2ecf20Sopenharmony_ci	return cc;
3548c2ecf20Sopenharmony_ci}
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ciint zpci_write_block(volatile void __iomem *dst,
3578c2ecf20Sopenharmony_ci		     const void *src, unsigned long len)
3588c2ecf20Sopenharmony_ci{
3598c2ecf20Sopenharmony_ci	u8 status;
3608c2ecf20Sopenharmony_ci	int cc;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	if (!static_branch_unlikely(&have_mio))
3638c2ecf20Sopenharmony_ci		return zpci_write_block_fh(dst, src, len);
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	cc = __pcistb_mio(src, (__force u64) dst, len, &status);
3668c2ecf20Sopenharmony_ci	if (cc)
3678c2ecf20Sopenharmony_ci		zpci_err_insn(cc, status, 0, (__force u64) dst);
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	return (cc > 0) ? -EIO : cc;
3708c2ecf20Sopenharmony_ci}
3718c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(zpci_write_block);
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_cistatic inline void __pciwb_mio(void)
3748c2ecf20Sopenharmony_ci{
3758c2ecf20Sopenharmony_ci	unsigned long unused = 0;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	asm volatile (".insn    rre,0xb9d50000,%[op],%[op]\n"
3788c2ecf20Sopenharmony_ci		      : [op] "+d" (unused));
3798c2ecf20Sopenharmony_ci}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_civoid zpci_barrier(void)
3828c2ecf20Sopenharmony_ci{
3838c2ecf20Sopenharmony_ci	if (static_branch_likely(&have_mio))
3848c2ecf20Sopenharmony_ci		__pciwb_mio();
3858c2ecf20Sopenharmony_ci}
3868c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(zpci_barrier);
387