18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci#ifndef _ASM_S390_PCI_IO_H 38c2ecf20Sopenharmony_ci#define _ASM_S390_PCI_IO_H 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/kernel.h> 88c2ecf20Sopenharmony_ci#include <linux/slab.h> 98c2ecf20Sopenharmony_ci#include <asm/pci_insn.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci/* I/O size constraints */ 128c2ecf20Sopenharmony_ci#define ZPCI_MAX_READ_SIZE 8 138c2ecf20Sopenharmony_ci#define ZPCI_MAX_WRITE_SIZE 128 148c2ecf20Sopenharmony_ci#define ZPCI_BOUNDARY_SIZE (1 << 12) 158c2ecf20Sopenharmony_ci#define ZPCI_BOUNDARY_MASK (ZPCI_BOUNDARY_SIZE - 1) 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci/* I/O Map */ 188c2ecf20Sopenharmony_ci#define ZPCI_IOMAP_SHIFT 48 198c2ecf20Sopenharmony_ci#define ZPCI_IOMAP_ADDR_SHIFT 62 208c2ecf20Sopenharmony_ci#define ZPCI_IOMAP_ADDR_BASE (1UL << ZPCI_IOMAP_ADDR_SHIFT) 218c2ecf20Sopenharmony_ci#define ZPCI_IOMAP_ADDR_OFF_MASK ((1UL << ZPCI_IOMAP_SHIFT) - 1) 228c2ecf20Sopenharmony_ci#define ZPCI_IOMAP_MAX_ENTRIES \ 238c2ecf20Sopenharmony_ci (1UL << (ZPCI_IOMAP_ADDR_SHIFT - ZPCI_IOMAP_SHIFT)) 248c2ecf20Sopenharmony_ci#define ZPCI_IOMAP_ADDR_IDX_MASK \ 258c2ecf20Sopenharmony_ci ((ZPCI_IOMAP_ADDR_BASE - 1) & ~ZPCI_IOMAP_ADDR_OFF_MASK) 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistruct zpci_iomap_entry { 288c2ecf20Sopenharmony_ci u32 fh; 298c2ecf20Sopenharmony_ci u8 bar; 308c2ecf20Sopenharmony_ci u16 count; 318c2ecf20Sopenharmony_ci}; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ciextern struct zpci_iomap_entry *zpci_iomap_start; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#define ZPCI_ADDR(idx) (ZPCI_IOMAP_ADDR_BASE | ((u64) idx << ZPCI_IOMAP_SHIFT)) 368c2ecf20Sopenharmony_ci#define ZPCI_IDX(addr) \ 378c2ecf20Sopenharmony_ci (((__force u64) addr & ZPCI_IOMAP_ADDR_IDX_MASK) >> ZPCI_IOMAP_SHIFT) 388c2ecf20Sopenharmony_ci#define ZPCI_OFFSET(addr) \ 398c2ecf20Sopenharmony_ci ((__force u64) addr & ZPCI_IOMAP_ADDR_OFF_MASK) 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#define ZPCI_CREATE_REQ(handle, space, len) \ 428c2ecf20Sopenharmony_ci ((u64) handle << 32 | space << 16 | len) 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#define zpci_read(LENGTH, RETTYPE) \ 458c2ecf20Sopenharmony_cistatic inline RETTYPE zpci_read_##RETTYPE(const volatile void __iomem *addr) \ 468c2ecf20Sopenharmony_ci{ \ 478c2ecf20Sopenharmony_ci u64 data; \ 488c2ecf20Sopenharmony_ci int rc; \ 498c2ecf20Sopenharmony_ci \ 508c2ecf20Sopenharmony_ci rc = zpci_load(&data, addr, LENGTH); \ 518c2ecf20Sopenharmony_ci if (rc) \ 528c2ecf20Sopenharmony_ci data = -1ULL; \ 538c2ecf20Sopenharmony_ci return (RETTYPE) data; \ 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#define zpci_write(LENGTH, VALTYPE) \ 578c2ecf20Sopenharmony_cistatic inline void zpci_write_##VALTYPE(VALTYPE val, \ 588c2ecf20Sopenharmony_ci const volatile void __iomem *addr) \ 598c2ecf20Sopenharmony_ci{ \ 608c2ecf20Sopenharmony_ci u64 data = (VALTYPE) val; \ 618c2ecf20Sopenharmony_ci \ 628c2ecf20Sopenharmony_ci zpci_store(addr, data, LENGTH); \ 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cizpci_read(8, u64) 668c2ecf20Sopenharmony_cizpci_read(4, u32) 678c2ecf20Sopenharmony_cizpci_read(2, u16) 688c2ecf20Sopenharmony_cizpci_read(1, u8) 698c2ecf20Sopenharmony_cizpci_write(8, u64) 708c2ecf20Sopenharmony_cizpci_write(4, u32) 718c2ecf20Sopenharmony_cizpci_write(2, u16) 728c2ecf20Sopenharmony_cizpci_write(1, u8) 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic inline int zpci_write_single(volatile void __iomem *dst, const void *src, 758c2ecf20Sopenharmony_ci unsigned long len) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci u64 val; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci switch (len) { 808c2ecf20Sopenharmony_ci case 1: 818c2ecf20Sopenharmony_ci val = (u64) *((u8 *) src); 828c2ecf20Sopenharmony_ci break; 838c2ecf20Sopenharmony_ci case 2: 848c2ecf20Sopenharmony_ci val = (u64) *((u16 *) src); 858c2ecf20Sopenharmony_ci break; 868c2ecf20Sopenharmony_ci case 4: 878c2ecf20Sopenharmony_ci val = (u64) *((u32 *) src); 888c2ecf20Sopenharmony_ci break; 898c2ecf20Sopenharmony_ci case 8: 908c2ecf20Sopenharmony_ci val = (u64) *((u64 *) src); 918c2ecf20Sopenharmony_ci break; 928c2ecf20Sopenharmony_ci default: 938c2ecf20Sopenharmony_ci val = 0; /* let FW report error */ 948c2ecf20Sopenharmony_ci break; 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci return zpci_store(dst, val, len); 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic inline int zpci_read_single(void *dst, const volatile void __iomem *src, 1008c2ecf20Sopenharmony_ci unsigned long len) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci u64 data; 1038c2ecf20Sopenharmony_ci int cc; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci cc = zpci_load(&data, src, len); 1068c2ecf20Sopenharmony_ci if (cc) 1078c2ecf20Sopenharmony_ci goto out; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci switch (len) { 1108c2ecf20Sopenharmony_ci case 1: 1118c2ecf20Sopenharmony_ci *((u8 *) dst) = (u8) data; 1128c2ecf20Sopenharmony_ci break; 1138c2ecf20Sopenharmony_ci case 2: 1148c2ecf20Sopenharmony_ci *((u16 *) dst) = (u16) data; 1158c2ecf20Sopenharmony_ci break; 1168c2ecf20Sopenharmony_ci case 4: 1178c2ecf20Sopenharmony_ci *((u32 *) dst) = (u32) data; 1188c2ecf20Sopenharmony_ci break; 1198c2ecf20Sopenharmony_ci case 8: 1208c2ecf20Sopenharmony_ci *((u64 *) dst) = (u64) data; 1218c2ecf20Sopenharmony_ci break; 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ciout: 1248c2ecf20Sopenharmony_ci return cc; 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ciint zpci_write_block(volatile void __iomem *dst, const void *src, 1288c2ecf20Sopenharmony_ci unsigned long len); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic inline int zpci_get_max_io_size(u64 src, u64 dst, int len, int max) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci int offset = dst & ZPCI_BOUNDARY_MASK; 1338c2ecf20Sopenharmony_ci int size; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci size = min3(len, ZPCI_BOUNDARY_SIZE - offset, max); 1368c2ecf20Sopenharmony_ci if (IS_ALIGNED(src, 8) && IS_ALIGNED(dst, 8) && IS_ALIGNED(size, 8)) 1378c2ecf20Sopenharmony_ci return size; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci if (size >= 8) 1408c2ecf20Sopenharmony_ci return 8; 1418c2ecf20Sopenharmony_ci return rounddown_pow_of_two(size); 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic inline int zpci_memcpy_fromio(void *dst, 1458c2ecf20Sopenharmony_ci const volatile void __iomem *src, 1468c2ecf20Sopenharmony_ci unsigned long n) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci int size, rc = 0; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci while (n > 0) { 1518c2ecf20Sopenharmony_ci size = zpci_get_max_io_size((u64 __force) src, 1528c2ecf20Sopenharmony_ci (u64) dst, n, 1538c2ecf20Sopenharmony_ci ZPCI_MAX_READ_SIZE); 1548c2ecf20Sopenharmony_ci rc = zpci_read_single(dst, src, size); 1558c2ecf20Sopenharmony_ci if (rc) 1568c2ecf20Sopenharmony_ci break; 1578c2ecf20Sopenharmony_ci src += size; 1588c2ecf20Sopenharmony_ci dst += size; 1598c2ecf20Sopenharmony_ci n -= size; 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci return rc; 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic inline int zpci_memcpy_toio(volatile void __iomem *dst, 1658c2ecf20Sopenharmony_ci const void *src, unsigned long n) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci int size, rc = 0; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci if (!src) 1708c2ecf20Sopenharmony_ci return -EINVAL; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci while (n > 0) { 1738c2ecf20Sopenharmony_ci size = zpci_get_max_io_size((u64 __force) dst, 1748c2ecf20Sopenharmony_ci (u64) src, n, 1758c2ecf20Sopenharmony_ci ZPCI_MAX_WRITE_SIZE); 1768c2ecf20Sopenharmony_ci if (size > 8) /* main path */ 1778c2ecf20Sopenharmony_ci rc = zpci_write_block(dst, src, size); 1788c2ecf20Sopenharmony_ci else 1798c2ecf20Sopenharmony_ci rc = zpci_write_single(dst, src, size); 1808c2ecf20Sopenharmony_ci if (rc) 1818c2ecf20Sopenharmony_ci break; 1828c2ecf20Sopenharmony_ci src += size; 1838c2ecf20Sopenharmony_ci dst += size; 1848c2ecf20Sopenharmony_ci n -= size; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci return rc; 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic inline int zpci_memset_io(volatile void __iomem *dst, 1908c2ecf20Sopenharmony_ci unsigned char val, size_t count) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci u8 *src = kmalloc(count, GFP_KERNEL); 1938c2ecf20Sopenharmony_ci int rc; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci if (src == NULL) 1968c2ecf20Sopenharmony_ci return -ENOMEM; 1978c2ecf20Sopenharmony_ci memset(src, val, count); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci rc = zpci_memcpy_toio(dst, src, count); 2008c2ecf20Sopenharmony_ci kfree(src); 2018c2ecf20Sopenharmony_ci return rc; 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci#endif /* CONFIG_PCI */ 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci#endif /* _ASM_S390_PCI_IO_H */ 207