1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2 /* Copyright (C) 2015-2018 Netronome Systems, Inc. */
3
4 /*
5 * nfp_cpplib.c
6 * Library of functions to access the NFP's CPP bus
7 * Authors: Jakub Kicinski <jakub.kicinski@netronome.com>
8 * Jason McMullan <jason.mcmullan@netronome.com>
9 * Rolf Neugebauer <rolf.neugebauer@netronome.com>
10 */
11
12 #include <asm/unaligned.h>
13 #include <linux/bitfield.h>
14 #include <linux/delay.h>
15 #include <linux/kernel.h>
16 #include <linux/module.h>
17 #include <linux/slab.h>
18 #include <linux/sched.h>
19
20 #include "nfp_cpp.h"
21 #include "nfp6000/nfp6000.h"
22 #include "nfp6000/nfp_xpb.h"
23
24 /* NFP6000 PL */
25 #define NFP_PL_DEVICE_ID 0x00000004
26 #define NFP_PL_DEVICE_ID_MASK GENMASK(7, 0)
27 #define NFP_PL_DEVICE_PART_MASK GENMASK(31, 16)
28 #define NFP_PL_DEVICE_MODEL_MASK (NFP_PL_DEVICE_PART_MASK | \
29 NFP_PL_DEVICE_ID_MASK)
30
31 /**
32 * nfp_cpp_readl() - Read a u32 word from a CPP location
33 * @cpp: CPP device handle
34 * @cpp_id: CPP ID for operation
35 * @address: Address for operation
36 * @value: Pointer to read buffer
37 *
38 * Return: 0 on success, or -ERRNO
39 */
nfp_cpp_readl(struct nfp_cpp * cpp,u32 cpp_id,unsigned long long address,u32 * value)40 int nfp_cpp_readl(struct nfp_cpp *cpp, u32 cpp_id,
41 unsigned long long address, u32 *value)
42 {
43 u8 tmp[4];
44 int n;
45
46 n = nfp_cpp_read(cpp, cpp_id, address, tmp, sizeof(tmp));
47 if (n != sizeof(tmp))
48 return n < 0 ? n : -EIO;
49
50 *value = get_unaligned_le32(tmp);
51 return 0;
52 }
53
54 /**
55 * nfp_cpp_writel() - Write a u32 word to a CPP location
56 * @cpp: CPP device handle
57 * @cpp_id: CPP ID for operation
58 * @address: Address for operation
59 * @value: Value to write
60 *
61 * Return: 0 on success, or -ERRNO
62 */
nfp_cpp_writel(struct nfp_cpp * cpp,u32 cpp_id,unsigned long long address,u32 value)63 int nfp_cpp_writel(struct nfp_cpp *cpp, u32 cpp_id,
64 unsigned long long address, u32 value)
65 {
66 u8 tmp[4];
67 int n;
68
69 put_unaligned_le32(value, tmp);
70 n = nfp_cpp_write(cpp, cpp_id, address, tmp, sizeof(tmp));
71
72 return n == sizeof(tmp) ? 0 : n < 0 ? n : -EIO;
73 }
74
75 /**
76 * nfp_cpp_readq() - Read a u64 word from a CPP location
77 * @cpp: CPP device handle
78 * @cpp_id: CPP ID for operation
79 * @address: Address for operation
80 * @value: Pointer to read buffer
81 *
82 * Return: 0 on success, or -ERRNO
83 */
nfp_cpp_readq(struct nfp_cpp * cpp,u32 cpp_id,unsigned long long address,u64 * value)84 int nfp_cpp_readq(struct nfp_cpp *cpp, u32 cpp_id,
85 unsigned long long address, u64 *value)
86 {
87 u8 tmp[8];
88 int n;
89
90 n = nfp_cpp_read(cpp, cpp_id, address, tmp, sizeof(tmp));
91 if (n != sizeof(tmp))
92 return n < 0 ? n : -EIO;
93
94 *value = get_unaligned_le64(tmp);
95 return 0;
96 }
97
98 /**
99 * nfp_cpp_writeq() - Write a u64 word to a CPP location
100 * @cpp: CPP device handle
101 * @cpp_id: CPP ID for operation
102 * @address: Address for operation
103 * @value: Value to write
104 *
105 * Return: 0 on success, or -ERRNO
106 */
nfp_cpp_writeq(struct nfp_cpp * cpp,u32 cpp_id,unsigned long long address,u64 value)107 int nfp_cpp_writeq(struct nfp_cpp *cpp, u32 cpp_id,
108 unsigned long long address, u64 value)
109 {
110 u8 tmp[8];
111 int n;
112
113 put_unaligned_le64(value, tmp);
114 n = nfp_cpp_write(cpp, cpp_id, address, tmp, sizeof(tmp));
115
116 return n == sizeof(tmp) ? 0 : n < 0 ? n : -EIO;
117 }
118
119 /* NOTE: This code should not use nfp_xpb_* functions,
120 * as those are model-specific
121 */
nfp_cpp_model_autodetect(struct nfp_cpp * cpp,u32 * model)122 int nfp_cpp_model_autodetect(struct nfp_cpp *cpp, u32 *model)
123 {
124 u32 reg;
125 int err;
126
127 err = nfp_xpb_readl(cpp, NFP_XPB_DEVICE(1, 1, 16) + NFP_PL_DEVICE_ID,
128 ®);
129 if (err < 0)
130 return err;
131
132 *model = reg & NFP_PL_DEVICE_MODEL_MASK;
133 if (*model & NFP_PL_DEVICE_ID_MASK)
134 *model -= 0x10;
135
136 return 0;
137 }
138
nfp_bytemask(int width,u64 addr)139 static u8 nfp_bytemask(int width, u64 addr)
140 {
141 if (width == 8)
142 return 0xff;
143 else if (width == 4)
144 return 0x0f << (addr & 4);
145 else if (width == 2)
146 return 0x03 << (addr & 6);
147 else if (width == 1)
148 return 0x01 << (addr & 7);
149 else
150 return 0;
151 }
152
nfp_cpp_explicit_read(struct nfp_cpp * cpp,u32 cpp_id,u64 addr,void * buff,size_t len,int width_read)153 int nfp_cpp_explicit_read(struct nfp_cpp *cpp, u32 cpp_id,
154 u64 addr, void *buff, size_t len, int width_read)
155 {
156 struct nfp_cpp_explicit *expl;
157 char *tmp = buff;
158 int err, i, incr;
159 u8 byte_mask;
160
161 if (len & (width_read - 1))
162 return -EINVAL;
163
164 expl = nfp_cpp_explicit_acquire(cpp);
165 if (!expl)
166 return -EBUSY;
167
168 incr = min_t(int, 16 * width_read, 128);
169 incr = min_t(int, incr, len);
170
171 /* Translate a NFP_CPP_ACTION_RW to action 0 */
172 if (NFP_CPP_ID_ACTION_of(cpp_id) == NFP_CPP_ACTION_RW)
173 cpp_id = NFP_CPP_ID(NFP_CPP_ID_TARGET_of(cpp_id), 0,
174 NFP_CPP_ID_TOKEN_of(cpp_id));
175
176 byte_mask = nfp_bytemask(width_read, addr);
177
178 nfp_cpp_explicit_set_target(expl, cpp_id,
179 incr / width_read - 1, byte_mask);
180 nfp_cpp_explicit_set_posted(expl, 1, 0, NFP_SIGNAL_PUSH,
181 0, NFP_SIGNAL_NONE);
182
183 for (i = 0; i < len; i += incr, addr += incr, tmp += incr) {
184 if (i + incr > len) {
185 incr = len - i;
186 nfp_cpp_explicit_set_target(expl, cpp_id,
187 incr / width_read - 1,
188 0xff);
189 }
190
191 err = nfp_cpp_explicit_do(expl, addr);
192 if (err < 0)
193 goto exit_release;
194
195 err = nfp_cpp_explicit_get(expl, tmp, incr);
196 if (err < 0)
197 goto exit_release;
198 }
199 err = len;
200 exit_release:
201 nfp_cpp_explicit_release(expl);
202
203 return err;
204 }
205
nfp_cpp_explicit_write(struct nfp_cpp * cpp,u32 cpp_id,u64 addr,const void * buff,size_t len,int width_write)206 int nfp_cpp_explicit_write(struct nfp_cpp *cpp, u32 cpp_id, u64 addr,
207 const void *buff, size_t len, int width_write)
208 {
209 struct nfp_cpp_explicit *expl;
210 const char *tmp = buff;
211 int err, i, incr;
212 u8 byte_mask;
213
214 if (len & (width_write - 1))
215 return -EINVAL;
216
217 expl = nfp_cpp_explicit_acquire(cpp);
218 if (!expl)
219 return -EBUSY;
220
221 incr = min_t(int, 16 * width_write, 128);
222 incr = min_t(int, incr, len);
223
224 /* Translate a NFP_CPP_ACTION_RW to action 1 */
225 if (NFP_CPP_ID_ACTION_of(cpp_id) == NFP_CPP_ACTION_RW)
226 cpp_id = NFP_CPP_ID(NFP_CPP_ID_TARGET_of(cpp_id), 1,
227 NFP_CPP_ID_TOKEN_of(cpp_id));
228
229 byte_mask = nfp_bytemask(width_write, addr);
230
231 nfp_cpp_explicit_set_target(expl, cpp_id,
232 incr / width_write - 1, byte_mask);
233 nfp_cpp_explicit_set_posted(expl, 1, 0, NFP_SIGNAL_PULL,
234 0, NFP_SIGNAL_NONE);
235
236 for (i = 0; i < len; i += incr, addr += incr, tmp += incr) {
237 if (i + incr > len) {
238 incr = len - i;
239 nfp_cpp_explicit_set_target(expl, cpp_id,
240 incr / width_write - 1,
241 0xff);
242 }
243
244 err = nfp_cpp_explicit_put(expl, tmp, incr);
245 if (err < 0)
246 goto exit_release;
247
248 err = nfp_cpp_explicit_do(expl, addr);
249 if (err < 0)
250 goto exit_release;
251 }
252 err = len;
253 exit_release:
254 nfp_cpp_explicit_release(expl);
255
256 return err;
257 }
258
259 /**
260 * nfp_cpp_map_area() - Helper function to map an area
261 * @cpp: NFP CPP handler
262 * @name: Name for the area
263 * @cpp_id: CPP ID for operation
264 * @addr: CPP address
265 * @size: Size of the area
266 * @area: Area handle (output)
267 *
268 * Map an area of IOMEM access. To undo the effect of this function call
269 * @nfp_cpp_area_release_free(*area).
270 *
271 * Return: Pointer to memory mapped area or ERR_PTR
272 */
273 u8 __iomem *
nfp_cpp_map_area(struct nfp_cpp * cpp,const char * name,u32 cpp_id,u64 addr,unsigned long size,struct nfp_cpp_area ** area)274 nfp_cpp_map_area(struct nfp_cpp *cpp, const char *name, u32 cpp_id, u64 addr,
275 unsigned long size, struct nfp_cpp_area **area)
276 {
277 u8 __iomem *res;
278
279 *area = nfp_cpp_area_alloc_acquire(cpp, name, cpp_id, addr, size);
280 if (!*area)
281 goto err_eio;
282
283 res = nfp_cpp_area_iomem(*area);
284 if (!res)
285 goto err_release_free;
286
287 return res;
288
289 err_release_free:
290 nfp_cpp_area_release_free(*area);
291 err_eio:
292 return (u8 __iomem *)ERR_PTR(-EIO);
293 }
294