xref: /linux/drivers/misc/ocxl/mmio.c (revision 1a59d1b8e05ea6ab45f7e18897de1ef0e6bc3da6)
1 // SPDX-License-Identifier: GPL-2.0+
2 // Copyright 2019 IBM Corp.
3 #include <linux/sched/mm.h>
4 #include "trace.h"
5 #include "ocxl_internal.h"
6 
7 int ocxl_global_mmio_read32(struct ocxl_afu *afu, size_t offset,
8 				enum ocxl_endian endian, u32 *val)
9 {
10 	if (offset > afu->config.global_mmio_size - 4)
11 		return -EINVAL;
12 
13 #ifdef __BIG_ENDIAN__
14 	if (endian == OCXL_HOST_ENDIAN)
15 		endian = OCXL_BIG_ENDIAN;
16 #endif
17 
18 	switch (endian) {
19 	case OCXL_BIG_ENDIAN:
20 		*val = readl_be((char *)afu->global_mmio_ptr + offset);
21 		break;
22 
23 	default:
24 		*val = readl((char *)afu->global_mmio_ptr + offset);
25 		break;
26 	}
27 
28 	return 0;
29 }
30 EXPORT_SYMBOL_GPL(ocxl_global_mmio_read32);
31 
32 int ocxl_global_mmio_read64(struct ocxl_afu *afu, size_t offset,
33 				enum ocxl_endian endian, u64 *val)
34 {
35 	if (offset > afu->config.global_mmio_size - 8)
36 		return -EINVAL;
37 
38 #ifdef __BIG_ENDIAN__
39 	if (endian == OCXL_HOST_ENDIAN)
40 		endian = OCXL_BIG_ENDIAN;
41 #endif
42 
43 	switch (endian) {
44 	case OCXL_BIG_ENDIAN:
45 		*val = readq_be((char *)afu->global_mmio_ptr + offset);
46 		break;
47 
48 	default:
49 		*val = readq((char *)afu->global_mmio_ptr + offset);
50 		break;
51 	}
52 
53 	return 0;
54 }
55 EXPORT_SYMBOL_GPL(ocxl_global_mmio_read64);
56 
57 int ocxl_global_mmio_write32(struct ocxl_afu *afu, size_t offset,
58 				enum ocxl_endian endian, u32 val)
59 {
60 	if (offset > afu->config.global_mmio_size - 4)
61 		return -EINVAL;
62 
63 #ifdef __BIG_ENDIAN__
64 	if (endian == OCXL_HOST_ENDIAN)
65 		endian = OCXL_BIG_ENDIAN;
66 #endif
67 
68 	switch (endian) {
69 	case OCXL_BIG_ENDIAN:
70 		writel_be(val, (char *)afu->global_mmio_ptr + offset);
71 		break;
72 
73 	default:
74 		writel(val, (char *)afu->global_mmio_ptr + offset);
75 		break;
76 	}
77 
78 
79 	return 0;
80 }
81 EXPORT_SYMBOL_GPL(ocxl_global_mmio_write32);
82 
83 int ocxl_global_mmio_write64(struct ocxl_afu *afu, size_t offset,
84 				enum ocxl_endian endian, u64 val)
85 {
86 	if (offset > afu->config.global_mmio_size - 8)
87 		return -EINVAL;
88 
89 #ifdef __BIG_ENDIAN__
90 	if (endian == OCXL_HOST_ENDIAN)
91 		endian = OCXL_BIG_ENDIAN;
92 #endif
93 
94 	switch (endian) {
95 	case OCXL_BIG_ENDIAN:
96 		writeq_be(val, (char *)afu->global_mmio_ptr + offset);
97 		break;
98 
99 	default:
100 		writeq(val, (char *)afu->global_mmio_ptr + offset);
101 		break;
102 	}
103 
104 
105 	return 0;
106 }
107 EXPORT_SYMBOL_GPL(ocxl_global_mmio_write64);
108 
109 int ocxl_global_mmio_set32(struct ocxl_afu *afu, size_t offset,
110 				enum ocxl_endian endian, u32 mask)
111 {
112 	u32 tmp;
113 
114 	if (offset > afu->config.global_mmio_size - 4)
115 		return -EINVAL;
116 
117 #ifdef __BIG_ENDIAN__
118 	if (endian == OCXL_HOST_ENDIAN)
119 		endian = OCXL_BIG_ENDIAN;
120 #endif
121 
122 	switch (endian) {
123 	case OCXL_BIG_ENDIAN:
124 		tmp = readl_be((char *)afu->global_mmio_ptr + offset);
125 		tmp |= mask;
126 		writel_be(tmp, (char *)afu->global_mmio_ptr + offset);
127 		break;
128 
129 	default:
130 		tmp = readl((char *)afu->global_mmio_ptr + offset);
131 		tmp |= mask;
132 		writel(tmp, (char *)afu->global_mmio_ptr + offset);
133 		break;
134 	}
135 
136 	return 0;
137 }
138 EXPORT_SYMBOL_GPL(ocxl_global_mmio_set32);
139 
140 int ocxl_global_mmio_set64(struct ocxl_afu *afu, size_t offset,
141 				enum ocxl_endian endian, u64 mask)
142 {
143 	u64 tmp;
144 
145 	if (offset > afu->config.global_mmio_size - 8)
146 		return -EINVAL;
147 
148 #ifdef __BIG_ENDIAN__
149 	if (endian == OCXL_HOST_ENDIAN)
150 		endian = OCXL_BIG_ENDIAN;
151 #endif
152 
153 	switch (endian) {
154 	case OCXL_BIG_ENDIAN:
155 		tmp = readq_be((char *)afu->global_mmio_ptr + offset);
156 		tmp |= mask;
157 		writeq_be(tmp, (char *)afu->global_mmio_ptr + offset);
158 		break;
159 
160 	default:
161 		tmp = readq((char *)afu->global_mmio_ptr + offset);
162 		tmp |= mask;
163 		writeq(tmp, (char *)afu->global_mmio_ptr + offset);
164 		break;
165 	}
166 
167 	return 0;
168 }
169 EXPORT_SYMBOL_GPL(ocxl_global_mmio_set64);
170 
171 int ocxl_global_mmio_clear32(struct ocxl_afu *afu, size_t offset,
172 				enum ocxl_endian endian, u32 mask)
173 {
174 	u32 tmp;
175 
176 	if (offset > afu->config.global_mmio_size - 4)
177 		return -EINVAL;
178 
179 #ifdef __BIG_ENDIAN__
180 	if (endian == OCXL_HOST_ENDIAN)
181 		endian = OCXL_BIG_ENDIAN;
182 #endif
183 
184 	switch (endian) {
185 	case OCXL_BIG_ENDIAN:
186 		tmp = readl_be((char *)afu->global_mmio_ptr + offset);
187 		tmp &= ~mask;
188 		writel_be(tmp, (char *)afu->global_mmio_ptr + offset);
189 		break;
190 
191 	default:
192 		tmp = readl((char *)afu->global_mmio_ptr + offset);
193 		tmp &= ~mask;
194 		writel(tmp, (char *)afu->global_mmio_ptr + offset);
195 		break;
196 	}
197 
198 
199 	return 0;
200 }
201 EXPORT_SYMBOL_GPL(ocxl_global_mmio_clear32);
202 
203 int ocxl_global_mmio_clear64(struct ocxl_afu *afu, size_t offset,
204 				enum ocxl_endian endian, u64 mask)
205 {
206 	u64 tmp;
207 
208 	if (offset > afu->config.global_mmio_size - 8)
209 		return -EINVAL;
210 
211 #ifdef __BIG_ENDIAN__
212 	if (endian == OCXL_HOST_ENDIAN)
213 		endian = OCXL_BIG_ENDIAN;
214 #endif
215 
216 	switch (endian) {
217 	case OCXL_BIG_ENDIAN:
218 		tmp = readq_be((char *)afu->global_mmio_ptr + offset);
219 		tmp &= ~mask;
220 		writeq_be(tmp, (char *)afu->global_mmio_ptr + offset);
221 		break;
222 
223 	default:
224 		tmp = readq((char *)afu->global_mmio_ptr + offset);
225 		tmp &= ~mask;
226 		writeq(tmp, (char *)afu->global_mmio_ptr + offset);
227 		break;
228 	}
229 
230 	writeq(tmp, (char *)afu->global_mmio_ptr + offset);
231 
232 	return 0;
233 }
234 EXPORT_SYMBOL_GPL(ocxl_global_mmio_clear64);
235