1 | // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) |
2 | /* Copyright (C) 2015-2018 Netronome Systems, Inc. */ |
3 | |
4 | /* |
5 | * nfp_cppcore.c |
6 | * Provides low-level access to the NFP's internal 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/delay.h> |
14 | #include <linux/device.h> |
15 | #include <linux/ioport.h> |
16 | #include <linux/kernel.h> |
17 | #include <linux/module.h> |
18 | #include <linux/mutex.h> |
19 | #include <linux/sched.h> |
20 | #include <linux/slab.h> |
21 | #include <linux/wait.h> |
22 | |
23 | #include "nfp_arm.h" |
24 | #include "nfp_cpp.h" |
25 | #include "nfp6000/nfp6000.h" |
26 | |
27 | #define NFP_ARM_GCSR_SOFTMODEL2 0x0000014c |
28 | #define NFP_ARM_GCSR_SOFTMODEL3 0x00000150 |
29 | |
30 | struct nfp_cpp_resource { |
31 | struct list_head list; |
32 | const char *name; |
33 | u32 cpp_id; |
34 | u64 start; |
35 | u64 end; |
36 | }; |
37 | |
38 | /** |
39 | * struct nfp_cpp - main nfpcore device structure |
40 | * Following fields are read-only after probe() exits or netdevs are spawned. |
41 | * @dev: embedded device structure |
42 | * @op: low-level implementation ops |
43 | * @priv: private data of the low-level implementation |
44 | * @model: chip model |
45 | * @interface: chip interface id we are using to reach it |
46 | * @serial: chip serial number |
47 | * @imb_cat_table: CPP Mapping Table |
48 | * @mu_locality_lsb: MU access type bit offset |
49 | * |
50 | * Following fields use explicit locking: |
51 | * @resource_list: NFP CPP resource list |
52 | * @resource_lock: protects @resource_list |
53 | * |
54 | * @area_cache_list: cached areas for cpp/xpb read/write speed up |
55 | * @area_cache_mutex: protects @area_cache_list |
56 | * |
57 | * @waitq: area wait queue |
58 | */ |
59 | struct nfp_cpp { |
60 | struct device dev; |
61 | |
62 | void *priv; |
63 | |
64 | u32 model; |
65 | u16 interface; |
66 | u8 serial[NFP_SERIAL_LEN]; |
67 | |
68 | const struct nfp_cpp_operations *op; |
69 | struct list_head resource_list; |
70 | rwlock_t resource_lock; |
71 | wait_queue_head_t waitq; |
72 | |
73 | u32 imb_cat_table[16]; |
74 | unsigned int mu_locality_lsb; |
75 | |
76 | struct mutex area_cache_mutex; |
77 | struct list_head area_cache_list; |
78 | }; |
79 | |
80 | /* Element of the area_cache_list */ |
81 | struct nfp_cpp_area_cache { |
82 | struct list_head entry; |
83 | u32 id; |
84 | u64 addr; |
85 | u32 size; |
86 | struct nfp_cpp_area *area; |
87 | }; |
88 | |
89 | struct nfp_cpp_area { |
90 | struct nfp_cpp *cpp; |
91 | struct kref kref; |
92 | atomic_t refcount; |
93 | struct mutex mutex; /* Lock for the area's refcount */ |
94 | unsigned long long offset; |
95 | unsigned long size; |
96 | struct nfp_cpp_resource resource; |
97 | void __iomem *iomem; |
98 | /* Here follows the 'priv' part of nfp_cpp_area. */ |
99 | }; |
100 | |
101 | struct nfp_cpp_explicit { |
102 | struct nfp_cpp *cpp; |
103 | struct nfp_cpp_explicit_command cmd; |
104 | /* Here follows the 'priv' part of nfp_cpp_area. */ |
105 | }; |
106 | |
107 | static void __resource_add(struct list_head *head, struct nfp_cpp_resource *res) |
108 | { |
109 | struct nfp_cpp_resource *tmp; |
110 | struct list_head *pos; |
111 | |
112 | list_for_each(pos, head) { |
113 | tmp = container_of(pos, struct nfp_cpp_resource, list); |
114 | |
115 | if (tmp->cpp_id > res->cpp_id) |
116 | break; |
117 | |
118 | if (tmp->cpp_id == res->cpp_id && tmp->start > res->start) |
119 | break; |
120 | } |
121 | |
122 | list_add_tail(new: &res->list, head: pos); |
123 | } |
124 | |
125 | static void __resource_del(struct nfp_cpp_resource *res) |
126 | { |
127 | list_del_init(entry: &res->list); |
128 | } |
129 | |
130 | static void __release_cpp_area(struct kref *kref) |
131 | { |
132 | struct nfp_cpp_area *area = |
133 | container_of(kref, struct nfp_cpp_area, kref); |
134 | struct nfp_cpp *cpp = nfp_cpp_area_cpp(cpp_area: area); |
135 | |
136 | if (area->cpp->op->area_cleanup) |
137 | area->cpp->op->area_cleanup(area); |
138 | |
139 | write_lock(&cpp->resource_lock); |
140 | __resource_del(res: &area->resource); |
141 | write_unlock(&cpp->resource_lock); |
142 | kfree(objp: area); |
143 | } |
144 | |
145 | static void nfp_cpp_area_put(struct nfp_cpp_area *area) |
146 | { |
147 | kref_put(kref: &area->kref, release: __release_cpp_area); |
148 | } |
149 | |
150 | static struct nfp_cpp_area *nfp_cpp_area_get(struct nfp_cpp_area *area) |
151 | { |
152 | kref_get(kref: &area->kref); |
153 | |
154 | return area; |
155 | } |
156 | |
157 | /** |
158 | * nfp_cpp_free() - free the CPP handle |
159 | * @cpp: CPP handle |
160 | */ |
161 | void nfp_cpp_free(struct nfp_cpp *cpp) |
162 | { |
163 | struct nfp_cpp_area_cache *cache, *ctmp; |
164 | struct nfp_cpp_resource *res, *rtmp; |
165 | |
166 | /* Remove all caches */ |
167 | list_for_each_entry_safe(cache, ctmp, &cpp->area_cache_list, entry) { |
168 | list_del(entry: &cache->entry); |
169 | if (cache->id) |
170 | nfp_cpp_area_release(area: cache->area); |
171 | nfp_cpp_area_free(area: cache->area); |
172 | kfree(objp: cache); |
173 | } |
174 | |
175 | /* There should be no dangling areas at this point */ |
176 | WARN_ON(!list_empty(&cpp->resource_list)); |
177 | |
178 | /* .. but if they weren't, try to clean up. */ |
179 | list_for_each_entry_safe(res, rtmp, &cpp->resource_list, list) { |
180 | struct nfp_cpp_area *area = container_of(res, |
181 | struct nfp_cpp_area, |
182 | resource); |
183 | |
184 | dev_err(cpp->dev.parent, "Dangling area: %d:%d:%d:0x%0llx-0x%0llx%s%s\n" , |
185 | NFP_CPP_ID_TARGET_of(res->cpp_id), |
186 | NFP_CPP_ID_ACTION_of(res->cpp_id), |
187 | NFP_CPP_ID_TOKEN_of(res->cpp_id), |
188 | res->start, res->end, |
189 | res->name ? " " : "" , |
190 | res->name ? res->name : "" ); |
191 | |
192 | if (area->cpp->op->area_release) |
193 | area->cpp->op->area_release(area); |
194 | |
195 | __release_cpp_area(kref: &area->kref); |
196 | } |
197 | |
198 | if (cpp->op->free) |
199 | cpp->op->free(cpp); |
200 | |
201 | device_unregister(dev: &cpp->dev); |
202 | |
203 | kfree(objp: cpp); |
204 | } |
205 | |
206 | /** |
207 | * nfp_cpp_model() - Retrieve the Model ID of the NFP |
208 | * @cpp: NFP CPP handle |
209 | * |
210 | * Return: NFP CPP Model ID |
211 | */ |
212 | u32 nfp_cpp_model(struct nfp_cpp *cpp) |
213 | { |
214 | return cpp->model; |
215 | } |
216 | |
217 | /** |
218 | * nfp_cpp_interface() - Retrieve the Interface ID of the NFP |
219 | * @cpp: NFP CPP handle |
220 | * |
221 | * Return: NFP CPP Interface ID |
222 | */ |
223 | u16 nfp_cpp_interface(struct nfp_cpp *cpp) |
224 | { |
225 | return cpp->interface; |
226 | } |
227 | |
228 | /** |
229 | * nfp_cpp_serial() - Retrieve the Serial ID of the NFP |
230 | * @cpp: NFP CPP handle |
231 | * @serial: Pointer to NFP serial number |
232 | * |
233 | * Return: Length of NFP serial number |
234 | */ |
235 | int nfp_cpp_serial(struct nfp_cpp *cpp, const u8 **serial) |
236 | { |
237 | *serial = &cpp->serial[0]; |
238 | return sizeof(cpp->serial); |
239 | } |
240 | |
241 | #define NFP_IMB_TGTADDRESSMODECFG_MODE_of(_x) (((_x) >> 13) & 0x7) |
242 | #define NFP_IMB_TGTADDRESSMODECFG_ADDRMODE BIT(12) |
243 | #define NFP_IMB_TGTADDRESSMODECFG_ADDRMODE_32_BIT 0 |
244 | #define NFP_IMB_TGTADDRESSMODECFG_ADDRMODE_40_BIT BIT(12) |
245 | |
246 | static int nfp_cpp_set_mu_locality_lsb(struct nfp_cpp *cpp) |
247 | { |
248 | unsigned int mode, addr40; |
249 | u32 imbcppat; |
250 | int res; |
251 | |
252 | imbcppat = cpp->imb_cat_table[NFP_CPP_TARGET_MU]; |
253 | mode = NFP_IMB_TGTADDRESSMODECFG_MODE_of(imbcppat); |
254 | addr40 = !!(imbcppat & NFP_IMB_TGTADDRESSMODECFG_ADDRMODE); |
255 | |
256 | res = nfp_cppat_mu_locality_lsb(mode, addr40); |
257 | if (res < 0) |
258 | return res; |
259 | cpp->mu_locality_lsb = res; |
260 | |
261 | return 0; |
262 | } |
263 | |
264 | unsigned int nfp_cpp_mu_locality_lsb(struct nfp_cpp *cpp) |
265 | { |
266 | return cpp->mu_locality_lsb; |
267 | } |
268 | |
269 | /** |
270 | * nfp_cpp_area_alloc_with_name() - allocate a new CPP area |
271 | * @cpp: CPP device handle |
272 | * @dest: NFP CPP ID |
273 | * @name: Name of region |
274 | * @address: Address of region |
275 | * @size: Size of region |
276 | * |
277 | * Allocate and initialize a CPP area structure. The area must later |
278 | * be locked down with an 'acquire' before it can be safely accessed. |
279 | * |
280 | * NOTE: @address and @size must be 32-bit aligned values. |
281 | * |
282 | * Return: NFP CPP area handle, or NULL |
283 | */ |
284 | struct nfp_cpp_area * |
285 | nfp_cpp_area_alloc_with_name(struct nfp_cpp *cpp, u32 dest, const char *name, |
286 | unsigned long long address, unsigned long size) |
287 | { |
288 | struct nfp_cpp_area *area; |
289 | u64 tmp64 = address; |
290 | int err, name_len; |
291 | |
292 | /* Remap from cpp_island to cpp_target */ |
293 | err = nfp_target_cpp(cpp_island_id: dest, cpp_island_address: tmp64, cpp_target_id: &dest, cpp_target_address: &tmp64, imb_table: cpp->imb_cat_table); |
294 | if (err < 0) |
295 | return NULL; |
296 | |
297 | address = tmp64; |
298 | |
299 | if (!name) |
300 | name = "(reserved)" ; |
301 | |
302 | name_len = strlen(name) + 1; |
303 | area = kzalloc(size: sizeof(*area) + cpp->op->area_priv_size + name_len, |
304 | GFP_KERNEL); |
305 | if (!area) |
306 | return NULL; |
307 | |
308 | area->cpp = cpp; |
309 | area->resource.name = (void *)area + sizeof(*area) + |
310 | cpp->op->area_priv_size; |
311 | memcpy((char *)area->resource.name, name, name_len); |
312 | |
313 | area->resource.cpp_id = dest; |
314 | area->resource.start = address; |
315 | area->resource.end = area->resource.start + size - 1; |
316 | INIT_LIST_HEAD(list: &area->resource.list); |
317 | |
318 | atomic_set(v: &area->refcount, i: 0); |
319 | kref_init(kref: &area->kref); |
320 | mutex_init(&area->mutex); |
321 | |
322 | if (cpp->op->area_init) { |
323 | int err; |
324 | |
325 | err = cpp->op->area_init(area, dest, address, size); |
326 | if (err < 0) { |
327 | kfree(objp: area); |
328 | return NULL; |
329 | } |
330 | } |
331 | |
332 | write_lock(&cpp->resource_lock); |
333 | __resource_add(head: &cpp->resource_list, res: &area->resource); |
334 | write_unlock(&cpp->resource_lock); |
335 | |
336 | area->offset = address; |
337 | area->size = size; |
338 | |
339 | return area; |
340 | } |
341 | |
342 | /** |
343 | * nfp_cpp_area_alloc() - allocate a new CPP area |
344 | * @cpp: CPP handle |
345 | * @dest: CPP id |
346 | * @address: Start address on CPP target |
347 | * @size: Size of area in bytes |
348 | * |
349 | * Allocate and initialize a CPP area structure. The area must later |
350 | * be locked down with an 'acquire' before it can be safely accessed. |
351 | * |
352 | * NOTE: @address and @size must be 32-bit aligned values. |
353 | * |
354 | * Return: NFP CPP Area handle, or NULL |
355 | */ |
356 | struct nfp_cpp_area * |
357 | nfp_cpp_area_alloc(struct nfp_cpp *cpp, u32 dest, |
358 | unsigned long long address, unsigned long size) |
359 | { |
360 | return nfp_cpp_area_alloc_with_name(cpp, dest, NULL, address, size); |
361 | } |
362 | |
363 | /** |
364 | * nfp_cpp_area_alloc_acquire() - allocate a new CPP area and lock it down |
365 | * @cpp: CPP handle |
366 | * @name: Name of region |
367 | * @dest: CPP id |
368 | * @address: Start address on CPP target |
369 | * @size: Size of area |
370 | * |
371 | * Allocate and initialize a CPP area structure, and lock it down so |
372 | * that it can be accessed directly. |
373 | * |
374 | * NOTE: @address and @size must be 32-bit aligned values. |
375 | * The area must also be 'released' when the structure is freed. |
376 | * |
377 | * Return: NFP CPP Area handle, or NULL |
378 | */ |
379 | struct nfp_cpp_area * |
380 | nfp_cpp_area_alloc_acquire(struct nfp_cpp *cpp, const char *name, u32 dest, |
381 | unsigned long long address, unsigned long size) |
382 | { |
383 | struct nfp_cpp_area *area; |
384 | |
385 | area = nfp_cpp_area_alloc_with_name(cpp, dest, name, address, size); |
386 | if (!area) |
387 | return NULL; |
388 | |
389 | if (nfp_cpp_area_acquire(area)) { |
390 | nfp_cpp_area_free(area); |
391 | return NULL; |
392 | } |
393 | |
394 | return area; |
395 | } |
396 | |
397 | /** |
398 | * nfp_cpp_area_free() - free up the CPP area |
399 | * @area: CPP area handle |
400 | * |
401 | * Frees up memory resources held by the CPP area. |
402 | */ |
403 | void nfp_cpp_area_free(struct nfp_cpp_area *area) |
404 | { |
405 | if (atomic_read(v: &area->refcount)) |
406 | nfp_warn(area->cpp, "Warning: freeing busy area\n" ); |
407 | nfp_cpp_area_put(area); |
408 | } |
409 | |
410 | static bool nfp_cpp_area_acquire_try(struct nfp_cpp_area *area, int *status) |
411 | { |
412 | *status = area->cpp->op->area_acquire(area); |
413 | |
414 | return *status != -EAGAIN; |
415 | } |
416 | |
417 | static int __nfp_cpp_area_acquire(struct nfp_cpp_area *area) |
418 | { |
419 | int err, status; |
420 | |
421 | if (atomic_inc_return(v: &area->refcount) > 1) |
422 | return 0; |
423 | |
424 | if (!area->cpp->op->area_acquire) |
425 | return 0; |
426 | |
427 | err = wait_event_interruptible(area->cpp->waitq, |
428 | nfp_cpp_area_acquire_try(area, &status)); |
429 | if (!err) |
430 | err = status; |
431 | if (err) { |
432 | nfp_warn(area->cpp, "Warning: area wait failed: %d\n" , err); |
433 | atomic_dec(v: &area->refcount); |
434 | return err; |
435 | } |
436 | |
437 | nfp_cpp_area_get(area); |
438 | |
439 | return 0; |
440 | } |
441 | |
442 | /** |
443 | * nfp_cpp_area_acquire() - lock down a CPP area for access |
444 | * @area: CPP area handle |
445 | * |
446 | * Locks down the CPP area for a potential long term activity. Area |
447 | * must always be locked down before being accessed. |
448 | * |
449 | * Return: 0, or -ERRNO |
450 | */ |
451 | int nfp_cpp_area_acquire(struct nfp_cpp_area *area) |
452 | { |
453 | int ret; |
454 | |
455 | mutex_lock(&area->mutex); |
456 | ret = __nfp_cpp_area_acquire(area); |
457 | mutex_unlock(lock: &area->mutex); |
458 | |
459 | return ret; |
460 | } |
461 | |
462 | /** |
463 | * nfp_cpp_area_acquire_nonblocking() - lock down a CPP area for access |
464 | * @area: CPP area handle |
465 | * |
466 | * Locks down the CPP area for a potential long term activity. Area |
467 | * must always be locked down before being accessed. |
468 | * |
469 | * NOTE: Returns -EAGAIN is no area is available |
470 | * |
471 | * Return: 0, or -ERRNO |
472 | */ |
473 | int nfp_cpp_area_acquire_nonblocking(struct nfp_cpp_area *area) |
474 | { |
475 | mutex_lock(&area->mutex); |
476 | if (atomic_inc_return(v: &area->refcount) == 1) { |
477 | if (area->cpp->op->area_acquire) { |
478 | int err; |
479 | |
480 | err = area->cpp->op->area_acquire(area); |
481 | if (err < 0) { |
482 | atomic_dec(v: &area->refcount); |
483 | mutex_unlock(lock: &area->mutex); |
484 | return err; |
485 | } |
486 | } |
487 | } |
488 | mutex_unlock(lock: &area->mutex); |
489 | |
490 | nfp_cpp_area_get(area); |
491 | return 0; |
492 | } |
493 | |
494 | /** |
495 | * nfp_cpp_area_release() - release a locked down CPP area |
496 | * @area: CPP area handle |
497 | * |
498 | * Releases a previously locked down CPP area. |
499 | */ |
500 | void nfp_cpp_area_release(struct nfp_cpp_area *area) |
501 | { |
502 | mutex_lock(&area->mutex); |
503 | /* Only call the release on refcount == 0 */ |
504 | if (atomic_dec_and_test(v: &area->refcount)) { |
505 | if (area->cpp->op->area_release) { |
506 | area->cpp->op->area_release(area); |
507 | /* Let anyone waiting for a BAR try to get one.. */ |
508 | wake_up_interruptible_all(&area->cpp->waitq); |
509 | } |
510 | } |
511 | mutex_unlock(lock: &area->mutex); |
512 | |
513 | nfp_cpp_area_put(area); |
514 | } |
515 | |
516 | /** |
517 | * nfp_cpp_area_release_free() - release CPP area and free it |
518 | * @area: CPP area handle |
519 | * |
520 | * Releases CPP area and frees up memory resources held by the it. |
521 | */ |
522 | void nfp_cpp_area_release_free(struct nfp_cpp_area *area) |
523 | { |
524 | nfp_cpp_area_release(area); |
525 | nfp_cpp_area_free(area); |
526 | } |
527 | |
528 | /** |
529 | * nfp_cpp_area_read() - read data from CPP area |
530 | * @area: CPP area handle |
531 | * @offset: offset into CPP area |
532 | * @kernel_vaddr: kernel address to put data into |
533 | * @length: number of bytes to read |
534 | * |
535 | * Read data from indicated CPP region. |
536 | * |
537 | * NOTE: @offset and @length must be 32-bit aligned values. |
538 | * Area must have been locked down with an 'acquire'. |
539 | * |
540 | * Return: length of io, or -ERRNO |
541 | */ |
542 | int nfp_cpp_area_read(struct nfp_cpp_area *area, |
543 | unsigned long offset, void *kernel_vaddr, |
544 | size_t length) |
545 | { |
546 | return area->cpp->op->area_read(area, kernel_vaddr, offset, length); |
547 | } |
548 | |
549 | /** |
550 | * nfp_cpp_area_write() - write data to CPP area |
551 | * @area: CPP area handle |
552 | * @offset: offset into CPP area |
553 | * @kernel_vaddr: kernel address to read data from |
554 | * @length: number of bytes to write |
555 | * |
556 | * Write data to indicated CPP region. |
557 | * |
558 | * NOTE: @offset and @length must be 32-bit aligned values. |
559 | * Area must have been locked down with an 'acquire'. |
560 | * |
561 | * Return: length of io, or -ERRNO |
562 | */ |
563 | int nfp_cpp_area_write(struct nfp_cpp_area *area, |
564 | unsigned long offset, const void *kernel_vaddr, |
565 | size_t length) |
566 | { |
567 | return area->cpp->op->area_write(area, kernel_vaddr, offset, length); |
568 | } |
569 | |
570 | /** |
571 | * nfp_cpp_area_size() - return size of a CPP area |
572 | * @cpp_area: CPP area handle |
573 | * |
574 | * Return: Size of the area |
575 | */ |
576 | size_t nfp_cpp_area_size(struct nfp_cpp_area *cpp_area) |
577 | { |
578 | return cpp_area->size; |
579 | } |
580 | |
581 | /** |
582 | * nfp_cpp_area_name() - return name of a CPP area |
583 | * @cpp_area: CPP area handle |
584 | * |
585 | * Return: Name of the area, or NULL |
586 | */ |
587 | const char *nfp_cpp_area_name(struct nfp_cpp_area *cpp_area) |
588 | { |
589 | return cpp_area->resource.name; |
590 | } |
591 | |
592 | /** |
593 | * nfp_cpp_area_priv() - return private struct for CPP area |
594 | * @cpp_area: CPP area handle |
595 | * |
596 | * Return: Private data for the CPP area |
597 | */ |
598 | void *nfp_cpp_area_priv(struct nfp_cpp_area *cpp_area) |
599 | { |
600 | return &cpp_area[1]; |
601 | } |
602 | |
603 | /** |
604 | * nfp_cpp_area_cpp() - return CPP handle for CPP area |
605 | * @cpp_area: CPP area handle |
606 | * |
607 | * Return: NFP CPP handle |
608 | */ |
609 | struct nfp_cpp *nfp_cpp_area_cpp(struct nfp_cpp_area *cpp_area) |
610 | { |
611 | return cpp_area->cpp; |
612 | } |
613 | |
614 | /** |
615 | * nfp_cpp_area_resource() - get resource |
616 | * @area: CPP area handle |
617 | * |
618 | * NOTE: Area must have been locked down with an 'acquire'. |
619 | * |
620 | * Return: struct resource pointer, or NULL |
621 | */ |
622 | struct resource *nfp_cpp_area_resource(struct nfp_cpp_area *area) |
623 | { |
624 | struct resource *res = NULL; |
625 | |
626 | if (area->cpp->op->area_resource) |
627 | res = area->cpp->op->area_resource(area); |
628 | |
629 | return res; |
630 | } |
631 | |
632 | /** |
633 | * nfp_cpp_area_phys() - get physical address of CPP area |
634 | * @area: CPP area handle |
635 | * |
636 | * NOTE: Area must have been locked down with an 'acquire'. |
637 | * |
638 | * Return: phy_addr_t of the area, or NULL |
639 | */ |
640 | phys_addr_t nfp_cpp_area_phys(struct nfp_cpp_area *area) |
641 | { |
642 | phys_addr_t addr = ~0; |
643 | |
644 | if (area->cpp->op->area_phys) |
645 | addr = area->cpp->op->area_phys(area); |
646 | |
647 | return addr; |
648 | } |
649 | |
650 | /** |
651 | * nfp_cpp_area_iomem() - get IOMEM region for CPP area |
652 | * @area: CPP area handle |
653 | * |
654 | * Returns an iomem pointer for use with readl()/writel() style |
655 | * operations. |
656 | * |
657 | * NOTE: Area must have been locked down with an 'acquire'. |
658 | * |
659 | * Return: __iomem pointer to the area, or NULL |
660 | */ |
661 | void __iomem *nfp_cpp_area_iomem(struct nfp_cpp_area *area) |
662 | { |
663 | void __iomem *iomem = NULL; |
664 | |
665 | if (area->cpp->op->area_iomem) |
666 | iomem = area->cpp->op->area_iomem(area); |
667 | |
668 | return iomem; |
669 | } |
670 | |
671 | /** |
672 | * nfp_cpp_area_readl() - Read a u32 word from an area |
673 | * @area: CPP Area handle |
674 | * @offset: Offset into area |
675 | * @value: Pointer to read buffer |
676 | * |
677 | * Return: 0 on success, or -ERRNO |
678 | */ |
679 | int nfp_cpp_area_readl(struct nfp_cpp_area *area, |
680 | unsigned long offset, u32 *value) |
681 | { |
682 | u8 tmp[4]; |
683 | int n; |
684 | |
685 | n = nfp_cpp_area_read(area, offset, kernel_vaddr: &tmp, length: sizeof(tmp)); |
686 | if (n != sizeof(tmp)) |
687 | return n < 0 ? n : -EIO; |
688 | |
689 | *value = get_unaligned_le32(p: tmp); |
690 | return 0; |
691 | } |
692 | |
693 | /** |
694 | * nfp_cpp_area_writel() - Write a u32 word to an area |
695 | * @area: CPP Area handle |
696 | * @offset: Offset into area |
697 | * @value: Value to write |
698 | * |
699 | * Return: 0 on success, or -ERRNO |
700 | */ |
701 | int nfp_cpp_area_writel(struct nfp_cpp_area *area, |
702 | unsigned long offset, u32 value) |
703 | { |
704 | u8 tmp[4]; |
705 | int n; |
706 | |
707 | put_unaligned_le32(val: value, p: tmp); |
708 | n = nfp_cpp_area_write(area, offset, kernel_vaddr: &tmp, length: sizeof(tmp)); |
709 | |
710 | return n == sizeof(tmp) ? 0 : n < 0 ? n : -EIO; |
711 | } |
712 | |
713 | /** |
714 | * nfp_cpp_area_readq() - Read a u64 word from an area |
715 | * @area: CPP Area handle |
716 | * @offset: Offset into area |
717 | * @value: Pointer to read buffer |
718 | * |
719 | * Return: 0 on success, or -ERRNO |
720 | */ |
721 | int nfp_cpp_area_readq(struct nfp_cpp_area *area, |
722 | unsigned long offset, u64 *value) |
723 | { |
724 | u8 tmp[8]; |
725 | int n; |
726 | |
727 | n = nfp_cpp_area_read(area, offset, kernel_vaddr: &tmp, length: sizeof(tmp)); |
728 | if (n != sizeof(tmp)) |
729 | return n < 0 ? n : -EIO; |
730 | |
731 | *value = get_unaligned_le64(p: tmp); |
732 | return 0; |
733 | } |
734 | |
735 | /** |
736 | * nfp_cpp_area_writeq() - Write a u64 word to an area |
737 | * @area: CPP Area handle |
738 | * @offset: Offset into area |
739 | * @value: Value to write |
740 | * |
741 | * Return: 0 on success, or -ERRNO |
742 | */ |
743 | int nfp_cpp_area_writeq(struct nfp_cpp_area *area, |
744 | unsigned long offset, u64 value) |
745 | { |
746 | u8 tmp[8]; |
747 | int n; |
748 | |
749 | put_unaligned_le64(val: value, p: tmp); |
750 | n = nfp_cpp_area_write(area, offset, kernel_vaddr: &tmp, length: sizeof(tmp)); |
751 | |
752 | return n == sizeof(tmp) ? 0 : n < 0 ? n : -EIO; |
753 | } |
754 | |
755 | /** |
756 | * nfp_cpp_area_fill() - fill a CPP area with a value |
757 | * @area: CPP area |
758 | * @offset: offset into CPP area |
759 | * @value: value to fill with |
760 | * @length: length of area to fill |
761 | * |
762 | * Fill indicated area with given value. |
763 | * |
764 | * Return: length of io, or -ERRNO |
765 | */ |
766 | int nfp_cpp_area_fill(struct nfp_cpp_area *area, |
767 | unsigned long offset, u32 value, size_t length) |
768 | { |
769 | u8 tmp[4]; |
770 | size_t i; |
771 | int k; |
772 | |
773 | put_unaligned_le32(val: value, p: tmp); |
774 | |
775 | if (offset % sizeof(tmp) || length % sizeof(tmp)) |
776 | return -EINVAL; |
777 | |
778 | for (i = 0; i < length; i += sizeof(tmp)) { |
779 | k = nfp_cpp_area_write(area, offset: offset + i, kernel_vaddr: &tmp, length: sizeof(tmp)); |
780 | if (k < 0) |
781 | return k; |
782 | } |
783 | |
784 | return i; |
785 | } |
786 | |
787 | /** |
788 | * nfp_cpp_area_cache_add() - Permanently reserve and area for the hot cache |
789 | * @cpp: NFP CPP handle |
790 | * @size: Size of the area - MUST BE A POWER OF 2. |
791 | */ |
792 | int nfp_cpp_area_cache_add(struct nfp_cpp *cpp, size_t size) |
793 | { |
794 | struct nfp_cpp_area_cache *cache; |
795 | struct nfp_cpp_area *area; |
796 | |
797 | /* Allocate an area - we use the MU target's base as a placeholder, |
798 | * as all supported chips have a MU. |
799 | */ |
800 | area = nfp_cpp_area_alloc(cpp, NFP_CPP_ID(7, NFP_CPP_ACTION_RW, 0), |
801 | address: 0, size); |
802 | if (!area) |
803 | return -ENOMEM; |
804 | |
805 | cache = kzalloc(size: sizeof(*cache), GFP_KERNEL); |
806 | if (!cache) { |
807 | nfp_cpp_area_free(area); |
808 | return -ENOMEM; |
809 | } |
810 | |
811 | cache->id = 0; |
812 | cache->addr = 0; |
813 | cache->size = size; |
814 | cache->area = area; |
815 | mutex_lock(&cpp->area_cache_mutex); |
816 | list_add_tail(new: &cache->entry, head: &cpp->area_cache_list); |
817 | mutex_unlock(lock: &cpp->area_cache_mutex); |
818 | |
819 | return 0; |
820 | } |
821 | |
822 | static struct nfp_cpp_area_cache * |
823 | area_cache_get(struct nfp_cpp *cpp, u32 id, |
824 | u64 addr, unsigned long *offset, size_t length) |
825 | { |
826 | struct nfp_cpp_area_cache *cache; |
827 | int err; |
828 | |
829 | /* Early exit when length == 0, which prevents |
830 | * the need for special case code below when |
831 | * checking against available cache size. |
832 | */ |
833 | if (length == 0 || id == 0) |
834 | return NULL; |
835 | |
836 | /* Remap from cpp_island to cpp_target */ |
837 | err = nfp_target_cpp(cpp_island_id: id, cpp_island_address: addr, cpp_target_id: &id, cpp_target_address: &addr, imb_table: cpp->imb_cat_table); |
838 | if (err < 0) |
839 | return NULL; |
840 | |
841 | mutex_lock(&cpp->area_cache_mutex); |
842 | |
843 | if (list_empty(head: &cpp->area_cache_list)) { |
844 | mutex_unlock(lock: &cpp->area_cache_mutex); |
845 | return NULL; |
846 | } |
847 | |
848 | addr += *offset; |
849 | |
850 | /* See if we have a match */ |
851 | list_for_each_entry(cache, &cpp->area_cache_list, entry) { |
852 | if (id == cache->id && |
853 | addr >= cache->addr && |
854 | addr + length <= cache->addr + cache->size) |
855 | goto exit; |
856 | } |
857 | |
858 | /* No matches - inspect the tail of the LRU */ |
859 | cache = list_entry(cpp->area_cache_list.prev, |
860 | struct nfp_cpp_area_cache, entry); |
861 | |
862 | /* Can we fit in the cache entry? */ |
863 | if (round_down(addr + length - 1, cache->size) != |
864 | round_down(addr, cache->size)) { |
865 | mutex_unlock(lock: &cpp->area_cache_mutex); |
866 | return NULL; |
867 | } |
868 | |
869 | /* If id != 0, we will need to release it */ |
870 | if (cache->id) { |
871 | nfp_cpp_area_release(area: cache->area); |
872 | cache->id = 0; |
873 | cache->addr = 0; |
874 | } |
875 | |
876 | /* Adjust the start address to be cache size aligned */ |
877 | cache->addr = addr & ~(u64)(cache->size - 1); |
878 | |
879 | /* Re-init to the new ID and address */ |
880 | if (cpp->op->area_init) { |
881 | err = cpp->op->area_init(cache->area, |
882 | id, cache->addr, cache->size); |
883 | if (err < 0) { |
884 | mutex_unlock(lock: &cpp->area_cache_mutex); |
885 | return NULL; |
886 | } |
887 | } |
888 | |
889 | /* Attempt to acquire */ |
890 | err = nfp_cpp_area_acquire(area: cache->area); |
891 | if (err < 0) { |
892 | mutex_unlock(lock: &cpp->area_cache_mutex); |
893 | return NULL; |
894 | } |
895 | |
896 | cache->id = id; |
897 | |
898 | exit: |
899 | /* Adjust offset */ |
900 | *offset = addr - cache->addr; |
901 | return cache; |
902 | } |
903 | |
904 | static void |
905 | area_cache_put(struct nfp_cpp *cpp, struct nfp_cpp_area_cache *cache) |
906 | { |
907 | if (!cache) |
908 | return; |
909 | |
910 | /* Move to front of LRU */ |
911 | list_move(list: &cache->entry, head: &cpp->area_cache_list); |
912 | |
913 | mutex_unlock(lock: &cpp->area_cache_mutex); |
914 | } |
915 | |
916 | static int __nfp_cpp_read(struct nfp_cpp *cpp, u32 destination, |
917 | unsigned long long address, void *kernel_vaddr, |
918 | size_t length) |
919 | { |
920 | struct nfp_cpp_area_cache *cache; |
921 | struct nfp_cpp_area *area; |
922 | unsigned long offset = 0; |
923 | int err; |
924 | |
925 | cache = area_cache_get(cpp, id: destination, addr: address, offset: &offset, length); |
926 | if (cache) { |
927 | area = cache->area; |
928 | } else { |
929 | area = nfp_cpp_area_alloc(cpp, dest: destination, address, size: length); |
930 | if (!area) |
931 | return -ENOMEM; |
932 | |
933 | err = nfp_cpp_area_acquire(area); |
934 | if (err) { |
935 | nfp_cpp_area_free(area); |
936 | return err; |
937 | } |
938 | } |
939 | |
940 | err = nfp_cpp_area_read(area, offset, kernel_vaddr, length); |
941 | |
942 | if (cache) |
943 | area_cache_put(cpp, cache); |
944 | else |
945 | nfp_cpp_area_release_free(area); |
946 | |
947 | return err; |
948 | } |
949 | |
950 | /** |
951 | * nfp_cpp_read() - read from CPP target |
952 | * @cpp: CPP handle |
953 | * @destination: CPP id |
954 | * @address: offset into CPP target |
955 | * @kernel_vaddr: kernel buffer for result |
956 | * @length: number of bytes to read |
957 | * |
958 | * Return: length of io, or -ERRNO |
959 | */ |
960 | int nfp_cpp_read(struct nfp_cpp *cpp, u32 destination, |
961 | unsigned long long address, void *kernel_vaddr, |
962 | size_t length) |
963 | { |
964 | size_t n, offset; |
965 | int ret; |
966 | |
967 | for (offset = 0; offset < length; offset += n) { |
968 | unsigned long long r_addr = address + offset; |
969 | |
970 | /* make first read smaller to align to safe window */ |
971 | n = min_t(size_t, length - offset, |
972 | ALIGN(r_addr + 1, NFP_CPP_SAFE_AREA_SIZE) - r_addr); |
973 | |
974 | ret = __nfp_cpp_read(cpp, destination, address: address + offset, |
975 | kernel_vaddr: kernel_vaddr + offset, length: n); |
976 | if (ret < 0) |
977 | return ret; |
978 | if (ret != n) |
979 | return offset + n; |
980 | } |
981 | |
982 | return length; |
983 | } |
984 | |
985 | static int __nfp_cpp_write(struct nfp_cpp *cpp, u32 destination, |
986 | unsigned long long address, |
987 | const void *kernel_vaddr, size_t length) |
988 | { |
989 | struct nfp_cpp_area_cache *cache; |
990 | struct nfp_cpp_area *area; |
991 | unsigned long offset = 0; |
992 | int err; |
993 | |
994 | cache = area_cache_get(cpp, id: destination, addr: address, offset: &offset, length); |
995 | if (cache) { |
996 | area = cache->area; |
997 | } else { |
998 | area = nfp_cpp_area_alloc(cpp, dest: destination, address, size: length); |
999 | if (!area) |
1000 | return -ENOMEM; |
1001 | |
1002 | err = nfp_cpp_area_acquire(area); |
1003 | if (err) { |
1004 | nfp_cpp_area_free(area); |
1005 | return err; |
1006 | } |
1007 | } |
1008 | |
1009 | err = nfp_cpp_area_write(area, offset, kernel_vaddr, length); |
1010 | |
1011 | if (cache) |
1012 | area_cache_put(cpp, cache); |
1013 | else |
1014 | nfp_cpp_area_release_free(area); |
1015 | |
1016 | return err; |
1017 | } |
1018 | |
1019 | /** |
1020 | * nfp_cpp_write() - write to CPP target |
1021 | * @cpp: CPP handle |
1022 | * @destination: CPP id |
1023 | * @address: offset into CPP target |
1024 | * @kernel_vaddr: kernel buffer to read from |
1025 | * @length: number of bytes to write |
1026 | * |
1027 | * Return: length of io, or -ERRNO |
1028 | */ |
1029 | int nfp_cpp_write(struct nfp_cpp *cpp, u32 destination, |
1030 | unsigned long long address, |
1031 | const void *kernel_vaddr, size_t length) |
1032 | { |
1033 | size_t n, offset; |
1034 | int ret; |
1035 | |
1036 | for (offset = 0; offset < length; offset += n) { |
1037 | unsigned long long w_addr = address + offset; |
1038 | |
1039 | /* make first write smaller to align to safe window */ |
1040 | n = min_t(size_t, length - offset, |
1041 | ALIGN(w_addr + 1, NFP_CPP_SAFE_AREA_SIZE) - w_addr); |
1042 | |
1043 | ret = __nfp_cpp_write(cpp, destination, address: address + offset, |
1044 | kernel_vaddr: kernel_vaddr + offset, length: n); |
1045 | if (ret < 0) |
1046 | return ret; |
1047 | if (ret != n) |
1048 | return offset + n; |
1049 | } |
1050 | |
1051 | return length; |
1052 | } |
1053 | |
1054 | /* Return the correct CPP address, and fixup xpb_addr as needed. */ |
1055 | static u32 nfp_xpb_to_cpp(struct nfp_cpp *cpp, u32 *xpb_addr) |
1056 | { |
1057 | int island; |
1058 | u32 xpb; |
1059 | |
1060 | xpb = NFP_CPP_ID(14, NFP_CPP_ACTION_RW, 0); |
1061 | /* Ensure that non-local XPB accesses go |
1062 | * out through the global XPBM bus. |
1063 | */ |
1064 | island = (*xpb_addr >> 24) & 0x3f; |
1065 | if (!island) |
1066 | return xpb; |
1067 | |
1068 | if (island != 1) { |
1069 | *xpb_addr |= 1 << 30; |
1070 | return xpb; |
1071 | } |
1072 | |
1073 | /* Accesses to the ARM Island overlay uses Island 0 / Global Bit */ |
1074 | *xpb_addr &= ~0x7f000000; |
1075 | if (*xpb_addr < 0x60000) { |
1076 | *xpb_addr |= 1 << 30; |
1077 | } else { |
1078 | /* And only non-ARM interfaces use the island id = 1 */ |
1079 | if (NFP_CPP_INTERFACE_TYPE_of(nfp_cpp_interface(cpp)) |
1080 | != NFP_CPP_INTERFACE_TYPE_ARM) |
1081 | *xpb_addr |= 1 << 24; |
1082 | } |
1083 | |
1084 | return xpb; |
1085 | } |
1086 | |
1087 | /** |
1088 | * nfp_xpb_readl() - Read a u32 word from a XPB location |
1089 | * @cpp: CPP device handle |
1090 | * @xpb_addr: Address for operation |
1091 | * @value: Pointer to read buffer |
1092 | * |
1093 | * Return: 0 on success, or -ERRNO |
1094 | */ |
1095 | int nfp_xpb_readl(struct nfp_cpp *cpp, u32 xpb_addr, u32 *value) |
1096 | { |
1097 | u32 cpp_dest = nfp_xpb_to_cpp(cpp, xpb_addr: &xpb_addr); |
1098 | |
1099 | return nfp_cpp_readl(cpp, cpp_id: cpp_dest, address: xpb_addr, value); |
1100 | } |
1101 | |
1102 | /** |
1103 | * nfp_xpb_writel() - Write a u32 word to a XPB location |
1104 | * @cpp: CPP device handle |
1105 | * @xpb_addr: Address for operation |
1106 | * @value: Value to write |
1107 | * |
1108 | * Return: 0 on success, or -ERRNO |
1109 | */ |
1110 | int nfp_xpb_writel(struct nfp_cpp *cpp, u32 xpb_addr, u32 value) |
1111 | { |
1112 | u32 cpp_dest = nfp_xpb_to_cpp(cpp, xpb_addr: &xpb_addr); |
1113 | |
1114 | return nfp_cpp_writel(cpp, cpp_id: cpp_dest, address: xpb_addr, value); |
1115 | } |
1116 | |
1117 | /** |
1118 | * nfp_xpb_writelm() - Modify bits of a 32-bit value from the XPB bus |
1119 | * @cpp: NFP CPP device handle |
1120 | * @xpb_tgt: XPB target and address |
1121 | * @mask: mask of bits to alter |
1122 | * @value: value to modify |
1123 | * |
1124 | * KERNEL: This operation is safe to call in interrupt or softirq context. |
1125 | * |
1126 | * Return: 0 on success, or -ERRNO |
1127 | */ |
1128 | int nfp_xpb_writelm(struct nfp_cpp *cpp, u32 xpb_tgt, |
1129 | u32 mask, u32 value) |
1130 | { |
1131 | int err; |
1132 | u32 tmp; |
1133 | |
1134 | err = nfp_xpb_readl(cpp, xpb_addr: xpb_tgt, value: &tmp); |
1135 | if (err < 0) |
1136 | return err; |
1137 | |
1138 | tmp &= ~mask; |
1139 | tmp |= mask & value; |
1140 | return nfp_xpb_writel(cpp, xpb_addr: xpb_tgt, value: tmp); |
1141 | } |
1142 | |
1143 | /* Lockdep markers */ |
1144 | static struct lock_class_key nfp_cpp_resource_lock_key; |
1145 | |
1146 | static void nfp_cpp_dev_release(struct device *dev) |
1147 | { |
1148 | /* Nothing to do here - it just makes the kernel happy */ |
1149 | } |
1150 | |
1151 | /** |
1152 | * nfp_cpp_from_operations() - Create a NFP CPP handle |
1153 | * from an operations structure |
1154 | * @ops: NFP CPP operations structure |
1155 | * @parent: Parent device |
1156 | * @priv: Private data of low-level implementation |
1157 | * |
1158 | * NOTE: On failure, cpp_ops->free will be called! |
1159 | * |
1160 | * Return: NFP CPP handle on success, ERR_PTR on failure |
1161 | */ |
1162 | struct nfp_cpp * |
1163 | nfp_cpp_from_operations(const struct nfp_cpp_operations *ops, |
1164 | struct device *parent, void *priv) |
1165 | { |
1166 | const u32 arm = NFP_CPP_ID(NFP_CPP_TARGET_ARM, NFP_CPP_ACTION_RW, 0); |
1167 | struct nfp_cpp *cpp; |
1168 | int ifc, err; |
1169 | u32 mask[2]; |
1170 | u32 xpbaddr; |
1171 | size_t tgt; |
1172 | |
1173 | cpp = kzalloc(size: sizeof(*cpp), GFP_KERNEL); |
1174 | if (!cpp) { |
1175 | err = -ENOMEM; |
1176 | goto err_malloc; |
1177 | } |
1178 | |
1179 | cpp->op = ops; |
1180 | cpp->priv = priv; |
1181 | |
1182 | ifc = ops->get_interface(parent); |
1183 | if (ifc < 0) { |
1184 | err = ifc; |
1185 | goto err_free_cpp; |
1186 | } |
1187 | cpp->interface = ifc; |
1188 | if (ops->read_serial) { |
1189 | err = ops->read_serial(parent, cpp->serial); |
1190 | if (err) |
1191 | goto err_free_cpp; |
1192 | } |
1193 | |
1194 | rwlock_init(&cpp->resource_lock); |
1195 | init_waitqueue_head(&cpp->waitq); |
1196 | lockdep_set_class(&cpp->resource_lock, &nfp_cpp_resource_lock_key); |
1197 | INIT_LIST_HEAD(list: &cpp->resource_list); |
1198 | INIT_LIST_HEAD(list: &cpp->area_cache_list); |
1199 | mutex_init(&cpp->area_cache_mutex); |
1200 | cpp->dev.init_name = "cpp" ; |
1201 | cpp->dev.parent = parent; |
1202 | cpp->dev.release = nfp_cpp_dev_release; |
1203 | err = device_register(dev: &cpp->dev); |
1204 | if (err < 0) { |
1205 | put_device(dev: &cpp->dev); |
1206 | goto err_free_cpp; |
1207 | } |
1208 | |
1209 | dev_set_drvdata(dev: &cpp->dev, data: cpp); |
1210 | |
1211 | /* NOTE: cpp_lock is NOT locked for op->init, |
1212 | * since it may call NFP CPP API operations |
1213 | */ |
1214 | if (cpp->op->init) { |
1215 | err = cpp->op->init(cpp); |
1216 | if (err < 0) { |
1217 | dev_err(parent, |
1218 | "NFP interface initialization failed\n" ); |
1219 | goto err_out; |
1220 | } |
1221 | } |
1222 | |
1223 | err = nfp_cpp_model_autodetect(cpp, model: &cpp->model); |
1224 | if (err < 0) { |
1225 | dev_err(parent, "NFP model detection failed\n" ); |
1226 | goto err_out; |
1227 | } |
1228 | |
1229 | for (tgt = 0; tgt < ARRAY_SIZE(cpp->imb_cat_table); tgt++) { |
1230 | /* Hardcoded XPB IMB Base, island 0 */ |
1231 | xpbaddr = 0x000a0000 + (tgt * 4); |
1232 | err = nfp_xpb_readl(cpp, xpb_addr: xpbaddr, |
1233 | value: &cpp->imb_cat_table[tgt]); |
1234 | if (err < 0) { |
1235 | dev_err(parent, |
1236 | "Can't read CPP mapping from device\n" ); |
1237 | goto err_out; |
1238 | } |
1239 | } |
1240 | |
1241 | nfp_cpp_readl(cpp, cpp_id: arm, NFP_ARM_GCSR + NFP_ARM_GCSR_SOFTMODEL2, |
1242 | value: &mask[0]); |
1243 | nfp_cpp_readl(cpp, cpp_id: arm, NFP_ARM_GCSR + NFP_ARM_GCSR_SOFTMODEL3, |
1244 | value: &mask[1]); |
1245 | |
1246 | err = nfp_cpp_set_mu_locality_lsb(cpp); |
1247 | if (err < 0) { |
1248 | dev_err(parent, "Can't calculate MU locality bit offset\n" ); |
1249 | goto err_out; |
1250 | } |
1251 | |
1252 | dev_info(cpp->dev.parent, "Model: 0x%08x, SN: %pM, Ifc: 0x%04x\n" , |
1253 | nfp_cpp_model(cpp), cpp->serial, nfp_cpp_interface(cpp)); |
1254 | |
1255 | return cpp; |
1256 | |
1257 | err_out: |
1258 | device_unregister(dev: &cpp->dev); |
1259 | err_free_cpp: |
1260 | kfree(objp: cpp); |
1261 | err_malloc: |
1262 | return ERR_PTR(error: err); |
1263 | } |
1264 | |
1265 | /** |
1266 | * nfp_cpp_priv() - Get the operations private data of a CPP handle |
1267 | * @cpp: CPP handle |
1268 | * |
1269 | * Return: Private data for the NFP CPP handle |
1270 | */ |
1271 | void *nfp_cpp_priv(struct nfp_cpp *cpp) |
1272 | { |
1273 | return cpp->priv; |
1274 | } |
1275 | |
1276 | /** |
1277 | * nfp_cpp_device() - Get the Linux device handle of a CPP handle |
1278 | * @cpp: CPP handle |
1279 | * |
1280 | * Return: Device for the NFP CPP bus |
1281 | */ |
1282 | struct device *nfp_cpp_device(struct nfp_cpp *cpp) |
1283 | { |
1284 | return &cpp->dev; |
1285 | } |
1286 | |
1287 | #define NFP_EXPL_OP(func, expl, args...) \ |
1288 | ({ \ |
1289 | struct nfp_cpp *cpp = nfp_cpp_explicit_cpp(expl); \ |
1290 | int err = -ENODEV; \ |
1291 | \ |
1292 | if (cpp->op->func) \ |
1293 | err = cpp->op->func(expl, ##args); \ |
1294 | err; \ |
1295 | }) |
1296 | |
1297 | #define NFP_EXPL_OP_NR(func, expl, args...) \ |
1298 | ({ \ |
1299 | struct nfp_cpp *cpp = nfp_cpp_explicit_cpp(expl); \ |
1300 | \ |
1301 | if (cpp->op->func) \ |
1302 | cpp->op->func(expl, ##args); \ |
1303 | \ |
1304 | }) |
1305 | |
1306 | /** |
1307 | * nfp_cpp_explicit_acquire() - Acquire explicit access handle |
1308 | * @cpp: NFP CPP handle |
1309 | * |
1310 | * The 'data_ref' and 'signal_ref' values are useful when |
1311 | * constructing the NFP_EXPL_CSR1 and NFP_EXPL_POST values. |
1312 | * |
1313 | * Return: NFP CPP explicit handle |
1314 | */ |
1315 | struct nfp_cpp_explicit *nfp_cpp_explicit_acquire(struct nfp_cpp *cpp) |
1316 | { |
1317 | struct nfp_cpp_explicit *expl; |
1318 | int err; |
1319 | |
1320 | expl = kzalloc(size: sizeof(*expl) + cpp->op->explicit_priv_size, GFP_KERNEL); |
1321 | if (!expl) |
1322 | return NULL; |
1323 | |
1324 | expl->cpp = cpp; |
1325 | err = NFP_EXPL_OP(explicit_acquire, expl); |
1326 | if (err < 0) { |
1327 | kfree(objp: expl); |
1328 | return NULL; |
1329 | } |
1330 | |
1331 | return expl; |
1332 | } |
1333 | |
1334 | /** |
1335 | * nfp_cpp_explicit_set_target() - Set target fields for explicit |
1336 | * @expl: Explicit handle |
1337 | * @cpp_id: CPP ID field |
1338 | * @len: CPP Length field |
1339 | * @mask: CPP Mask field |
1340 | * |
1341 | * Return: 0, or -ERRNO |
1342 | */ |
1343 | int nfp_cpp_explicit_set_target(struct nfp_cpp_explicit *expl, |
1344 | u32 cpp_id, u8 len, u8 mask) |
1345 | { |
1346 | expl->cmd.cpp_id = cpp_id; |
1347 | expl->cmd.len = len; |
1348 | expl->cmd.byte_mask = mask; |
1349 | |
1350 | return 0; |
1351 | } |
1352 | |
1353 | /** |
1354 | * nfp_cpp_explicit_set_data() - Set data fields for explicit |
1355 | * @expl: Explicit handle |
1356 | * @data_master: CPP Data Master field |
1357 | * @data_ref: CPP Data Ref field |
1358 | * |
1359 | * Return: 0, or -ERRNO |
1360 | */ |
1361 | int nfp_cpp_explicit_set_data(struct nfp_cpp_explicit *expl, |
1362 | u8 data_master, u16 data_ref) |
1363 | { |
1364 | expl->cmd.data_master = data_master; |
1365 | expl->cmd.data_ref = data_ref; |
1366 | |
1367 | return 0; |
1368 | } |
1369 | |
1370 | /** |
1371 | * nfp_cpp_explicit_set_signal() - Set signal fields for explicit |
1372 | * @expl: Explicit handle |
1373 | * @signal_master: CPP Signal Master field |
1374 | * @signal_ref: CPP Signal Ref field |
1375 | * |
1376 | * Return: 0, or -ERRNO |
1377 | */ |
1378 | int nfp_cpp_explicit_set_signal(struct nfp_cpp_explicit *expl, |
1379 | u8 signal_master, u8 signal_ref) |
1380 | { |
1381 | expl->cmd.signal_master = signal_master; |
1382 | expl->cmd.signal_ref = signal_ref; |
1383 | |
1384 | return 0; |
1385 | } |
1386 | |
1387 | /** |
1388 | * nfp_cpp_explicit_set_posted() - Set completion fields for explicit |
1389 | * @expl: Explicit handle |
1390 | * @posted: True for signaled completion, false otherwise |
1391 | * @siga: CPP Signal A field |
1392 | * @siga_mode: CPP Signal A Mode field |
1393 | * @sigb: CPP Signal B field |
1394 | * @sigb_mode: CPP Signal B Mode field |
1395 | * |
1396 | * Return: 0, or -ERRNO |
1397 | */ |
1398 | int nfp_cpp_explicit_set_posted(struct nfp_cpp_explicit *expl, int posted, |
1399 | u8 siga, |
1400 | enum nfp_cpp_explicit_signal_mode siga_mode, |
1401 | u8 sigb, |
1402 | enum nfp_cpp_explicit_signal_mode sigb_mode) |
1403 | { |
1404 | expl->cmd.posted = posted; |
1405 | expl->cmd.siga = siga; |
1406 | expl->cmd.sigb = sigb; |
1407 | expl->cmd.siga_mode = siga_mode; |
1408 | expl->cmd.sigb_mode = sigb_mode; |
1409 | |
1410 | return 0; |
1411 | } |
1412 | |
1413 | /** |
1414 | * nfp_cpp_explicit_put() - Set up the write (pull) data for a explicit access |
1415 | * @expl: NFP CPP Explicit handle |
1416 | * @buff: Data to have the target pull in the transaction |
1417 | * @len: Length of data, in bytes |
1418 | * |
1419 | * The 'len' parameter must be less than or equal to 128 bytes. |
1420 | * |
1421 | * If this function is called before the configuration |
1422 | * registers are set, it will return -EINVAL. |
1423 | * |
1424 | * Return: 0, or -ERRNO |
1425 | */ |
1426 | int nfp_cpp_explicit_put(struct nfp_cpp_explicit *expl, |
1427 | const void *buff, size_t len) |
1428 | { |
1429 | return NFP_EXPL_OP(explicit_put, expl, buff, len); |
1430 | } |
1431 | |
1432 | /** |
1433 | * nfp_cpp_explicit_do() - Execute a transaction, and wait for it to complete |
1434 | * @expl: NFP CPP Explicit handle |
1435 | * @address: Address to send in the explicit transaction |
1436 | * |
1437 | * If this function is called before the configuration |
1438 | * registers are set, it will return -1, with an errno of EINVAL. |
1439 | * |
1440 | * Return: 0, or -ERRNO |
1441 | */ |
1442 | int nfp_cpp_explicit_do(struct nfp_cpp_explicit *expl, u64 address) |
1443 | { |
1444 | return NFP_EXPL_OP(explicit_do, expl, &expl->cmd, address); |
1445 | } |
1446 | |
1447 | /** |
1448 | * nfp_cpp_explicit_get() - Get the 'push' (read) data from a explicit access |
1449 | * @expl: NFP CPP Explicit handle |
1450 | * @buff: Data that the target pushed in the transaction |
1451 | * @len: Length of data, in bytes |
1452 | * |
1453 | * The 'len' parameter must be less than or equal to 128 bytes. |
1454 | * |
1455 | * If this function is called before all three configuration |
1456 | * registers are set, it will return -1, with an errno of EINVAL. |
1457 | * |
1458 | * If this function is called before nfp_cpp_explicit_do() |
1459 | * has completed, it will return -1, with an errno of EBUSY. |
1460 | * |
1461 | * Return: 0, or -ERRNO |
1462 | */ |
1463 | int nfp_cpp_explicit_get(struct nfp_cpp_explicit *expl, void *buff, size_t len) |
1464 | { |
1465 | return NFP_EXPL_OP(explicit_get, expl, buff, len); |
1466 | } |
1467 | |
1468 | /** |
1469 | * nfp_cpp_explicit_release() - Release explicit access handle |
1470 | * @expl: NFP CPP Explicit handle |
1471 | * |
1472 | */ |
1473 | void nfp_cpp_explicit_release(struct nfp_cpp_explicit *expl) |
1474 | { |
1475 | NFP_EXPL_OP_NR(explicit_release, expl); |
1476 | kfree(objp: expl); |
1477 | } |
1478 | |
1479 | /** |
1480 | * nfp_cpp_explicit_cpp() - return CPP handle for CPP explicit |
1481 | * @cpp_explicit: CPP explicit handle |
1482 | * |
1483 | * Return: NFP CPP handle of the explicit |
1484 | */ |
1485 | struct nfp_cpp *nfp_cpp_explicit_cpp(struct nfp_cpp_explicit *cpp_explicit) |
1486 | { |
1487 | return cpp_explicit->cpp; |
1488 | } |
1489 | |
1490 | /** |
1491 | * nfp_cpp_explicit_priv() - return private struct for CPP explicit |
1492 | * @cpp_explicit: CPP explicit handle |
1493 | * |
1494 | * Return: private data of the explicit, or NULL |
1495 | */ |
1496 | void *nfp_cpp_explicit_priv(struct nfp_cpp_explicit *cpp_explicit) |
1497 | { |
1498 | return &cpp_explicit[1]; |
1499 | } |
1500 | |