Merge patch series "riscv: support fast gup"
[linux-2.6-microblaze.git] / drivers / misc / ocxl / mmio.c
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);