xref: /openbmc/linux/arch/s390/include/asm/pci_io.h (revision 2ae2e7cf)
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 
27 struct zpci_iomap_entry {
28 	u32 fh;
29 	u8 bar;
30 	u16 count;
31 };
32 
33 extern 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)						\
45 static 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)						\
57 static 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 
65 zpci_read(8, u64)
66 zpci_read(4, u32)
67 zpci_read(2, u16)
68 zpci_read(1, u8)
69 zpci_write(8, u64)
70 zpci_write(4, u32)
71 zpci_write(2, u16)
72 zpci_write(1, u8)
73 
74 static 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 
99 static 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 	}
123 out:
124 	return cc;
125 }
126 
127 int zpci_write_block(volatile void __iomem *dst, const void *src,
128 		     unsigned long len);
129 
130 static 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 
144 static 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 
164 static 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 
189 static 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