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
7int 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}
30EXPORT_SYMBOL_GPL(ocxl_global_mmio_read32);
31
32int 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}
55EXPORT_SYMBOL_GPL(ocxl_global_mmio_read64);
56
57int 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}
81EXPORT_SYMBOL_GPL(ocxl_global_mmio_write32);
82
83int 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}
107EXPORT_SYMBOL_GPL(ocxl_global_mmio_write64);
108
109int 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}
138EXPORT_SYMBOL_GPL(ocxl_global_mmio_set32);
139
140int 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}
169EXPORT_SYMBOL_GPL(ocxl_global_mmio_set64);
170
171int 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}
201EXPORT_SYMBOL_GPL(ocxl_global_mmio_clear32);
202
203int 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}
234EXPORT_SYMBOL_GPL(ocxl_global_mmio_clear64);
235