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