1/* SPDX-License-Identifier: GPL-2.0 */
2#ifndef _ASM_S390_PCI_IO_H
3#define _ASM_S390_PCI_IO_H
4
5#ifdef CONFIG_PCI
6
7#include <linux/kernel.h>
8#include <linux/slab.h>
9#include <asm/pci_insn.h>
10
11/* I/O size constraints */
12#define ZPCI_MAX_READ_SIZE	8
13#define ZPCI_MAX_WRITE_SIZE	128
14#define ZPCI_BOUNDARY_SIZE	(1 << 12)
15#define ZPCI_BOUNDARY_MASK	(ZPCI_BOUNDARY_SIZE - 1)
16
17/* I/O Map */
18#define ZPCI_IOMAP_SHIFT		48
19#define ZPCI_IOMAP_ADDR_SHIFT		62
20#define ZPCI_IOMAP_ADDR_BASE		(1UL << ZPCI_IOMAP_ADDR_SHIFT)
21#define ZPCI_IOMAP_ADDR_OFF_MASK	((1UL << ZPCI_IOMAP_SHIFT) - 1)
22#define ZPCI_IOMAP_MAX_ENTRIES							\
23	(1UL << (ZPCI_IOMAP_ADDR_SHIFT - ZPCI_IOMAP_SHIFT))
24#define ZPCI_IOMAP_ADDR_IDX_MASK						\
25	((ZPCI_IOMAP_ADDR_BASE - 1) & ~ZPCI_IOMAP_ADDR_OFF_MASK)
26
27struct zpci_iomap_entry {
28	u32 fh;
29	u8 bar;
30	u16 count;
31};
32
33extern struct zpci_iomap_entry *zpci_iomap_start;
34
35#define ZPCI_ADDR(idx) (ZPCI_IOMAP_ADDR_BASE | ((u64) idx << ZPCI_IOMAP_SHIFT))
36#define ZPCI_IDX(addr)								\
37	(((__force u64) addr & ZPCI_IOMAP_ADDR_IDX_MASK) >> ZPCI_IOMAP_SHIFT)
38#define ZPCI_OFFSET(addr)							\
39	((__force u64) addr & ZPCI_IOMAP_ADDR_OFF_MASK)
40
41#define ZPCI_CREATE_REQ(handle, space, len)					\
42	((u64) handle << 32 | space << 16 | len)
43
44#define zpci_read(LENGTH, RETTYPE)						\
45static inline RETTYPE zpci_read_##RETTYPE(const volatile void __iomem *addr)	\
46{										\
47	u64 data;								\
48	int rc;									\
49										\
50	rc = zpci_load(&data, addr, LENGTH);					\
51	if (rc)									\
52		data = -1ULL;							\
53	return (RETTYPE) data;							\
54}
55
56#define zpci_write(LENGTH, VALTYPE)						\
57static inline void zpci_write_##VALTYPE(VALTYPE val,				\
58					const volatile void __iomem *addr)	\
59{										\
60	u64 data = (VALTYPE) val;						\
61										\
62	zpci_store(addr, data, LENGTH);						\
63}
64
65zpci_read(8, u64)
66zpci_read(4, u32)
67zpci_read(2, u16)
68zpci_read(1, u8)
69zpci_write(8, u64)
70zpci_write(4, u32)
71zpci_write(2, u16)
72zpci_write(1, u8)
73
74static inline int zpci_write_single(volatile void __iomem *dst, const void *src,
75				    unsigned long len)
76{
77	u64 val;
78
79	switch (len) {
80	case 1:
81		val = (u64) *((u8 *) src);
82		break;
83	case 2:
84		val = (u64) *((u16 *) src);
85		break;
86	case 4:
87		val = (u64) *((u32 *) src);
88		break;
89	case 8:
90		val = (u64) *((u64 *) src);
91		break;
92	default:
93		val = 0;		/* let FW report error */
94		break;
95	}
96	return zpci_store(dst, val, len);
97}
98
99static inline int zpci_read_single(void *dst, const volatile void __iomem *src,
100				   unsigned long len)
101{
102	u64 data;
103	int cc;
104
105	cc = zpci_load(&data, src, len);
106	if (cc)
107		goto out;
108
109	switch (len) {
110	case 1:
111		*((u8 *) dst) = (u8) data;
112		break;
113	case 2:
114		*((u16 *) dst) = (u16) data;
115		break;
116	case 4:
117		*((u32 *) dst) = (u32) data;
118		break;
119	case 8:
120		*((u64 *) dst) = (u64) data;
121		break;
122	}
123out:
124	return cc;
125}
126
127int zpci_write_block(volatile void __iomem *dst, const void *src,
128		     unsigned long len);
129
130static inline int zpci_get_max_io_size(u64 src, u64 dst, int len, int max)
131{
132	int offset = dst & ZPCI_BOUNDARY_MASK;
133	int size;
134
135	size = min3(len, ZPCI_BOUNDARY_SIZE - offset, max);
136	if (IS_ALIGNED(src, 8) && IS_ALIGNED(dst, 8) && IS_ALIGNED(size, 8))
137		return size;
138
139	if (size >= 8)
140		return 8;
141	return rounddown_pow_of_two(size);
142}
143
144static inline int zpci_memcpy_fromio(void *dst,
145				     const volatile void __iomem *src,
146				     unsigned long n)
147{
148	int size, rc = 0;
149
150	while (n > 0) {
151		size = zpci_get_max_io_size((u64 __force) src,
152					    (u64) dst, n,
153					    ZPCI_MAX_READ_SIZE);
154		rc = zpci_read_single(dst, src, size);
155		if (rc)
156			break;
157		src += size;
158		dst += size;
159		n -= size;
160	}
161	return rc;
162}
163
164static inline int zpci_memcpy_toio(volatile void __iomem *dst,
165				   const void *src, unsigned long n)
166{
167	int size, rc = 0;
168
169	if (!src)
170		return -EINVAL;
171
172	while (n > 0) {
173		size = zpci_get_max_io_size((u64 __force) dst,
174					    (u64) src, n,
175					    ZPCI_MAX_WRITE_SIZE);
176		if (size > 8) /* main path */
177			rc = zpci_write_block(dst, src, size);
178		else
179			rc = zpci_write_single(dst, src, size);
180		if (rc)
181			break;
182		src += size;
183		dst += size;
184		n -= size;
185	}
186	return rc;
187}
188
189static inline int zpci_memset_io(volatile void __iomem *dst,
190				 unsigned char val, size_t count)
191{
192	u8 *src = kmalloc(count, GFP_KERNEL);
193	int rc;
194
195	if (src == NULL)
196		return -ENOMEM;
197	memset(src, val, count);
198
199	rc = zpci_memcpy_toio(dst, src, count);
200	kfree(src);
201	return rc;
202}
203
204#endif /* CONFIG_PCI */
205
206#endif /* _ASM_S390_PCI_IO_H */
207