Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2018 Netronome Systems, Inc.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : /*
7 : : * nfp_cpp_pcie_ops.c
8 : : * Authors: Vinayak Tammineedi <vinayak.tammineedi@netronome.com>
9 : : *
10 : : * Multiplexes the NFP BARs between NFP internal resources and
11 : : * implements the PCIe specific interface for generic CPP bus access.
12 : : *
13 : : * The BARs are managed and allocated if they are available.
14 : : * The generic CPP bus abstraction builds upon this BAR interface.
15 : : */
16 : :
17 : : #include "nfp6000_pcie.h"
18 : :
19 : : #include <unistd.h>
20 : : #include <fcntl.h>
21 : :
22 : : #include <rte_io.h>
23 : :
24 : : #include "nfp_cpp.h"
25 : : #include "nfp_logs.h"
26 : : #include "nfp_target.h"
27 : : #include "nfp6000/nfp6000.h"
28 : : #include "../nfp_logs.h"
29 : :
30 : : #define NFP_PCIE_BAR(_pf) (0x30000 + ((_pf) & 7) * 0xc0)
31 : :
32 : : #define NFP_PCIE_BAR_PCIE2CPP_ACTION_BASEADDRESS(_x) (((_x) & 0x1f) << 16)
33 : : #define NFP_PCIE_BAR_PCIE2CPP_ACTION_BASEADDRESS_OF(_x) (((_x) >> 16) & 0x1f)
34 : : #define NFP_PCIE_BAR_PCIE2CPP_BASEADDRESS(_x) (((_x) & 0xffff) << 0)
35 : : #define NFP_PCIE_BAR_PCIE2CPP_BASEADDRESS_OF(_x) (((_x) >> 0) & 0xffff)
36 : : #define NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT(_x) (((_x) & 0x3) << 27)
37 : : #define NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT_OF(_x) (((_x) >> 27) & 0x3)
38 : : #define NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT_32BIT 0
39 : : #define NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT_64BIT 1
40 : : #define NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT_0BYTE 3
41 : : #define NFP_PCIE_BAR_PCIE2CPP_MAPTYPE(_x) (((_x) & 0x7) << 29)
42 : : #define NFP_PCIE_BAR_PCIE2CPP_MAPTYPE_OF(_x) (((_x) >> 29) & 0x7)
43 : : #define NFP_PCIE_BAR_PCIE2CPP_MAPTYPE_FIXED 0
44 : : #define NFP_PCIE_BAR_PCIE2CPP_MAPTYPE_BULK 1
45 : : #define NFP_PCIE_BAR_PCIE2CPP_MAPTYPE_TARGET 2
46 : : #define NFP_PCIE_BAR_PCIE2CPP_MAPTYPE_GENERAL 3
47 : : #define NFP_PCIE_BAR_PCIE2CPP_TARGET_BASEADDRESS(_x) (((_x) & 0xf) << 23)
48 : : #define NFP_PCIE_BAR_PCIE2CPP_TARGET_BASEADDRESS_OF(_x) (((_x) >> 23) & 0xf)
49 : : #define NFP_PCIE_BAR_PCIE2CPP_TOKEN_BASEADDRESS(_x) (((_x) & 0x3) << 21)
50 : : #define NFP_PCIE_BAR_PCIE2CPP_TOKEN_BASEADDRESS_OF(_x) (((_x) >> 21) & 0x3)
51 : :
52 : : /*
53 : : * Minimal size of the PCIe cfg memory we depend on being mapped,
54 : : * queue controller and DMA controller don't have to be covered.
55 : : */
56 : : #define NFP_PCI_MIN_MAP_SIZE 0x080000 /* 512K */
57 : :
58 : : #define NFP_PCIE_P2C_FIXED_SIZE(bar) (1 << (bar)->bitsize)
59 : : #define NFP_PCIE_P2C_BULK_SIZE(bar) (1 << (bar)->bitsize)
60 : : #define NFP_PCIE_P2C_GENERAL_TARGET_OFFSET(bar, x) ((x) << ((bar)->bitsize - 2))
61 : : #define NFP_PCIE_P2C_GENERAL_TOKEN_OFFSET(bar, x) ((x) << ((bar)->bitsize - 4))
62 : : #define NFP_PCIE_P2C_GENERAL_SIZE(bar) (1 << ((bar)->bitsize - 4))
63 : :
64 : : #define NFP_PCIE_P2C_EXPBAR_OFFSET(bar_index) ((bar_index) * 4)
65 : :
66 : : struct nfp_pcie_user;
67 : : struct nfp6000_area_priv;
68 : :
69 : : /* Describes BAR configuration and usage */
70 : : struct nfp_bar {
71 : : struct nfp_pcie_user *nfp; /**< Backlink to owner */
72 : : uint32_t barcfg; /**< BAR config CSR */
73 : : uint64_t base; /**< Base CPP offset */
74 : : uint64_t mask; /**< Mask of the BAR aperture (read only) */
75 : : uint32_t bitsize; /**< Bit size of the BAR aperture (read only) */
76 : : uint32_t index; /**< Index of the BAR */
77 : : bool lock; /**< If the BAR has been locked */
78 : :
79 : : char *iomem; /**< mapped IO memory */
80 : : struct rte_mem_resource *resource; /**< IOMEM resource window */
81 : : };
82 : :
83 : : #define NFP_PCI_BAR_MAX (PCI_64BIT_BAR_COUNT * 8)
84 : :
85 : : struct nfp_pcie_user {
86 : : struct rte_pci_device *pci_dev;
87 : : const struct nfp_dev_info *dev_info;
88 : :
89 : : int lock;
90 : :
91 : : /* PCI BAR management */
92 : : uint32_t bars;
93 : : struct nfp_bar bar[NFP_PCI_BAR_MAX];
94 : :
95 : : /* Reserved BAR access */
96 : : char *csr;
97 : : };
98 : :
99 : : /* Generic CPP bus access interface. */
100 : : struct nfp6000_area_priv {
101 : : struct nfp_bar *bar;
102 : : uint32_t bar_offset;
103 : :
104 : : int target;
105 : : int action;
106 : : int token;
107 : : uint64_t offset;
108 : : struct {
109 : : int read;
110 : : int write;
111 : : int bar;
112 : : } width;
113 : : size_t size;
114 : : char *iomem;
115 : : };
116 : :
117 : : static uint32_t
118 : : nfp_bar_maptype(struct nfp_bar *bar)
119 : : {
120 : 0 : return NFP_PCIE_BAR_PCIE2CPP_MAPTYPE_OF(bar->barcfg);
121 : : }
122 : :
123 : : #define TARGET_WIDTH_32 4
124 : : #define TARGET_WIDTH_64 8
125 : :
126 : : static int
127 : 0 : nfp_compute_bar(const struct nfp_bar *bar,
128 : : uint32_t *bar_config,
129 : : uint64_t *bar_base,
130 : : int target,
131 : : int action,
132 : : int token,
133 : : uint64_t offset,
134 : : size_t size,
135 : : int width)
136 : : {
137 : : uint64_t mask;
138 : : uint32_t newcfg;
139 : : uint32_t bitsize;
140 : :
141 [ # # ]: 0 : if (target >= NFP_CPP_NUM_TARGETS)
142 : : return -EINVAL;
143 : :
144 [ # # # # ]: 0 : switch (width) {
145 : : case 8:
146 : : newcfg = NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT
147 : : (NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT_64BIT);
148 : : break;
149 : 0 : case 4:
150 : : newcfg = NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT
151 : : (NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT_32BIT);
152 : 0 : break;
153 : 0 : case 0:
154 : : newcfg = NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT
155 : : (NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT_0BYTE);
156 : 0 : break;
157 : : default:
158 : : return -EINVAL;
159 : : }
160 : :
161 [ # # ]: 0 : if (action != NFP_CPP_ACTION_RW && action != 0) {
162 : : /* Fixed CPP mapping with specific action */
163 : 0 : mask = ~(NFP_PCIE_P2C_FIXED_SIZE(bar) - 1);
164 : :
165 : : newcfg |= NFP_PCIE_BAR_PCIE2CPP_MAPTYPE
166 : : (NFP_PCIE_BAR_PCIE2CPP_MAPTYPE_FIXED);
167 : 0 : newcfg |= NFP_PCIE_BAR_PCIE2CPP_TARGET_BASEADDRESS(target);
168 : 0 : newcfg |= NFP_PCIE_BAR_PCIE2CPP_ACTION_BASEADDRESS(action);
169 : 0 : newcfg |= NFP_PCIE_BAR_PCIE2CPP_TOKEN_BASEADDRESS(token);
170 : :
171 [ # # ]: 0 : if ((offset & mask) != ((offset + size - 1) & mask))
172 : : return -EINVAL;
173 : :
174 : : offset &= mask;
175 : : bitsize = 40 - 16;
176 : : } else {
177 : 0 : mask = ~(NFP_PCIE_P2C_BULK_SIZE(bar) - 1);
178 : :
179 : : /* Bulk mapping */
180 : 0 : newcfg |= NFP_PCIE_BAR_PCIE2CPP_MAPTYPE
181 : : (NFP_PCIE_BAR_PCIE2CPP_MAPTYPE_BULK);
182 : 0 : newcfg |= NFP_PCIE_BAR_PCIE2CPP_TARGET_BASEADDRESS(target);
183 : 0 : newcfg |= NFP_PCIE_BAR_PCIE2CPP_TOKEN_BASEADDRESS(token);
184 : :
185 [ # # ]: 0 : if ((offset & mask) != ((offset + size - 1) & mask))
186 : : return -EINVAL;
187 : :
188 : : offset &= mask;
189 : : bitsize = 40 - 21;
190 : : }
191 : 0 : newcfg |= offset >> bitsize;
192 : :
193 [ # # ]: 0 : if (bar_base != NULL)
194 : 0 : *bar_base = offset;
195 : :
196 [ # # ]: 0 : if (bar_config != NULL)
197 : 0 : *bar_config = newcfg;
198 : :
199 : : return 0;
200 : : }
201 : :
202 : : static int
203 : 0 : nfp_bar_write(struct nfp_pcie_user *nfp,
204 : : struct nfp_bar *bar,
205 : : uint32_t newcfg)
206 : : {
207 : : uint32_t xbar;
208 : :
209 : 0 : xbar = NFP_PCIE_P2C_EXPBAR_OFFSET(bar->index);
210 : :
211 [ # # ]: 0 : if (nfp->csr != NULL) {
212 : 0 : rte_write32(newcfg, nfp->csr + xbar);
213 : : /* Readback to ensure BAR is flushed */
214 : 0 : rte_read32(nfp->csr + xbar);
215 : : } else {
216 : 0 : xbar += nfp->dev_info->pcie_cfg_expbar_offset;
217 [ # # ]: 0 : if (rte_pci_write_config(nfp->pci_dev, &newcfg, sizeof(uint32_t),
218 : : xbar) < 0)
219 : : return -EIO;
220 : : }
221 : :
222 : 0 : bar->barcfg = newcfg;
223 : :
224 : 0 : return 0;
225 : : }
226 : :
227 : : static int
228 : 0 : nfp_reconfigure_bar(struct nfp_pcie_user *nfp,
229 : : struct nfp_bar *bar,
230 : : int target,
231 : : int action,
232 : : int token,
233 : : uint64_t offset,
234 : : size_t size,
235 : : int width)
236 : : {
237 : : int err;
238 : : uint32_t newcfg;
239 : : uint64_t newbase;
240 : :
241 : 0 : err = nfp_compute_bar(bar, &newcfg, &newbase, target, action,
242 : : token, offset, size, width);
243 [ # # ]: 0 : if (err != 0)
244 : : return err;
245 : :
246 : 0 : bar->base = newbase;
247 : :
248 : 0 : return nfp_bar_write(nfp, bar, newcfg);
249 : : }
250 : :
251 : : static uint32_t
252 : : nfp_bitsize_calc(uint64_t mask)
253 : : {
254 : : uint64_t tmp = mask;
255 : : uint32_t bit_size = 0;
256 : :
257 : 0 : if (tmp == 0)
258 : : return 0;
259 : :
260 [ # # ]: 0 : for (; tmp != 0; tmp >>= 1)
261 : 0 : bit_size++;
262 : :
263 : : return bit_size;
264 : : }
265 : :
266 : : static int
267 : 0 : nfp_cmp_bars(const void *ptr_a,
268 : : const void *ptr_b)
269 : : {
270 : : const struct nfp_bar *a = ptr_a;
271 : : const struct nfp_bar *b = ptr_b;
272 : :
273 [ # # ]: 0 : if (a->bitsize == b->bitsize)
274 : 0 : return a->index - b->index;
275 : : else
276 : 0 : return a->bitsize - b->bitsize;
277 : : }
278 : :
279 : : static bool
280 : : nfp_bars_for_secondary(uint32_t index)
281 : : {
282 : 0 : uint8_t tmp = index & 0x07;
283 : :
284 [ # # # # ]: 0 : if (tmp == 0x06 || tmp == 0x07)
285 : : return true;
286 : : else
287 : : return false;
288 : : }
289 : :
290 : : /**
291 : : * Map all PCI bars and fetch the actual BAR configurations from the board.
292 : : * We assume that the BAR with the PCIe config block is already mapped.
293 : : *
294 : : * BAR0.0: Reserved for General Mapping (for MSI-X access to PCIe SRAM)
295 : : * BAR0.1: --
296 : : * BAR0.2: --
297 : : * BAR0.3: --
298 : : * BAR0.4: --
299 : : * BAR0.5: --
300 : : * BAR0.6: --
301 : : * BAR0.7: --
302 : : *
303 : : * BAR1.0-BAR1.7: --
304 : : * BAR2.0-BAR2.7: --
305 : : */
306 : : static int
307 : 0 : nfp_enable_bars(struct nfp_pcie_user *nfp)
308 : : {
309 : : int pf;
310 : : uint32_t i;
311 : : uint8_t min_bars;
312 : : struct nfp_bar *bar;
313 : : enum rte_proc_type_t type;
314 : : struct rte_mem_resource *res;
315 : : const uint32_t barcfg_msix_general = NFP_PCIE_BAR_PCIE2CPP_MAPTYPE
316 : : (NFP_PCIE_BAR_PCIE2CPP_MAPTYPE_GENERAL) |
317 : : NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT_32BIT;
318 : :
319 : 0 : type = rte_eal_process_type();
320 [ # # ]: 0 : if (type == RTE_PROC_PRIMARY)
321 : : min_bars = 12;
322 : : else
323 : : min_bars = 4;
324 : :
325 [ # # ]: 0 : for (i = 0; i < RTE_DIM(nfp->bar); i++) {
326 [ # # ]: 0 : if (i != 0) {
327 [ # # ]: 0 : if (type == RTE_PROC_PRIMARY) {
328 : 0 : if (nfp_bars_for_secondary(i))
329 : 0 : continue;
330 : : } else {
331 : 0 : if (!nfp_bars_for_secondary(i))
332 : 0 : continue;
333 : : }
334 : : }
335 : :
336 : : /* 24 NFP bars mapping into BAR0, BAR2 and BAR4 */
337 : 0 : res = &nfp->pci_dev->mem_resource[(i >> 3) * 2];
338 : :
339 : : /* Skip over BARs that are not mapped */
340 [ # # ]: 0 : if (res->addr != NULL) {
341 : : bar = &nfp->bar[i];
342 : 0 : bar->resource = res;
343 : 0 : bar->barcfg = 0;
344 : :
345 : 0 : bar->nfp = nfp;
346 : 0 : bar->index = i;
347 : : /* The resource shared by 8 bars */
348 [ # # ]: 0 : bar->mask = (res->len >> 3) - 1;
349 : 0 : bar->bitsize = nfp_bitsize_calc(bar->mask);
350 : 0 : bar->base = 0;
351 : 0 : bar->lock = false;
352 : 0 : bar->iomem = (char *)res->addr +
353 : 0 : ((bar->index & 7) << bar->bitsize);
354 : :
355 : 0 : nfp->bars++;
356 : : }
357 : : }
358 : :
359 [ # # ]: 0 : if (nfp->bars < min_bars) {
360 : 0 : PMD_DRV_LOG(ERR, "Not enough usable BARs found.");
361 : 0 : return -EINVAL;
362 : : }
363 : :
364 [ # # # ]: 0 : switch (nfp->pci_dev->id.device_id) {
365 : 0 : case PCI_DEVICE_ID_NFP3800_PF_NIC:
366 : 0 : pf = nfp->pci_dev->addr.function & 0x07;
367 : 0 : nfp->csr = nfp->bar[0].iomem + NFP_PCIE_BAR(pf);
368 : 0 : break;
369 : 0 : case PCI_DEVICE_ID_NFP4000_PF_NIC:
370 : : case PCI_DEVICE_ID_NFP6000_PF_NIC:
371 : 0 : nfp->csr = nfp->bar[0].iomem + NFP_PCIE_BAR(0);
372 : 0 : break;
373 : 0 : default:
374 : 0 : PMD_DRV_LOG(ERR, "Unsupported device ID: %04hx!",
375 : : nfp->pci_dev->id.device_id);
376 : 0 : return -EINVAL;
377 : : }
378 : :
379 : : /* Configure, and lock, BAR0.0 for General Target use (MSI-X SRAM) */
380 : 0 : bar = &nfp->bar[0];
381 : 0 : bar->lock = true;
382 : :
383 [ # # ]: 0 : if (nfp_bar_write(nfp, bar, barcfg_msix_general) < 0)
384 : : return -EIO;
385 : :
386 : : /* Sort bars by bit size - use the smallest possible first. */
387 : 0 : qsort(&nfp->bar[0], nfp->bars, sizeof(nfp->bar[0]), nfp_cmp_bars);
388 : :
389 : 0 : return 0;
390 : : }
391 : :
392 : : /* Check if BAR can be used with the given parameters. */
393 : : static bool
394 : 0 : matching_bar_exist(struct nfp_bar *bar,
395 : : int target,
396 : : int action,
397 : : int token,
398 : : uint64_t offset,
399 : : size_t size,
400 : : int width)
401 : : {
402 : : int bar_width;
403 : : int bar_token;
404 : : int bar_target;
405 : : int bar_action;
406 : : uint32_t map_type;
407 : :
408 [ # # ]: 0 : bar_width = NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT_OF(bar->barcfg);
409 : : switch (bar_width) {
410 : : case NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT_32BIT:
411 : : bar_width = 4;
412 : : break;
413 : : case NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT_64BIT:
414 : : bar_width = 8;
415 : : break;
416 : : case NFP_PCIE_BAR_PCIE2CPP_LENGTHSELECT_0BYTE:
417 : : bar_width = 0;
418 : : break;
419 : : default:
420 : : bar_width = -1;
421 : : break;
422 : : }
423 : :
424 : : /* Make sure to match up the width */
425 [ # # ]: 0 : if (bar_width != width)
426 : : return false;
427 : :
428 : 0 : bar_token = NFP_PCIE_BAR_PCIE2CPP_TOKEN_BASEADDRESS_OF(bar->barcfg);
429 : 0 : bar_action = NFP_PCIE_BAR_PCIE2CPP_ACTION_BASEADDRESS_OF(bar->barcfg);
430 : 0 : map_type = NFP_PCIE_BAR_PCIE2CPP_MAPTYPE_OF(bar->barcfg);
431 [ # # # # ]: 0 : switch (map_type) {
432 : 0 : case NFP_PCIE_BAR_PCIE2CPP_MAPTYPE_TARGET:
433 : : bar_token = -1;
434 : : /* FALLTHROUGH */
435 : 0 : case NFP_PCIE_BAR_PCIE2CPP_MAPTYPE_BULK:
436 : : bar_action = NFP_CPP_ACTION_RW;
437 [ # # ]: 0 : if (action == 0)
438 : : action = NFP_CPP_ACTION_RW;
439 : : /* FALLTHROUGH */
440 : : case NFP_PCIE_BAR_PCIE2CPP_MAPTYPE_FIXED:
441 : : break;
442 : : default:
443 : : /* We don't match explicit bars through the area interface */
444 : : return false;
445 : : }
446 : :
447 : 0 : bar_target = NFP_PCIE_BAR_PCIE2CPP_TARGET_BASEADDRESS_OF(bar->barcfg);
448 [ # # ]: 0 : if ((bar_target < 0 || bar_target == target) &&
449 [ # # # # ]: 0 : (bar_token < 0 || bar_token == token) &&
450 : 0 : bar_action == action &&
451 [ # # ]: 0 : bar->base <= offset &&
452 [ # # ]: 0 : (bar->base + (1 << bar->bitsize)) >= (offset + size))
453 : 0 : return true;
454 : :
455 : : /* No match */
456 : : return false;
457 : : }
458 : :
459 : : static int
460 : 0 : find_matching_bar(struct nfp_pcie_user *nfp,
461 : : int target,
462 : : int action,
463 : : int token,
464 : : uint64_t offset,
465 : : size_t size,
466 : : int width)
467 : : {
468 : : uint32_t n;
469 : :
470 [ # # ]: 0 : for (n = 0; n < nfp->bars; n++) {
471 : 0 : struct nfp_bar *bar = &nfp->bar[n];
472 : :
473 [ # # ]: 0 : if (bar->lock)
474 : 0 : continue;
475 : :
476 [ # # ]: 0 : if (matching_bar_exist(bar, target, action, token,
477 : : offset, size, width))
478 : 0 : return n;
479 : : }
480 : :
481 : : return -1;
482 : : }
483 : :
484 : : /* Return EAGAIN if no resource is available */
485 : : static int
486 : 0 : find_unused_bar_noblock(struct nfp_pcie_user *nfp,
487 : : int target,
488 : : int action,
489 : : int token,
490 : : uint64_t offset,
491 : : size_t size,
492 : : int width)
493 : : {
494 : : int ret;
495 : : uint32_t n;
496 : : const struct nfp_bar *bar;
497 : :
498 [ # # ]: 0 : for (n = 0; n < nfp->bars; n++) {
499 : 0 : bar = &nfp->bar[n];
500 : :
501 [ # # ]: 0 : if (bar->bitsize == 0)
502 : 0 : continue;
503 : :
504 : : /* Just check to see if we can make it fit... */
505 : 0 : ret = nfp_compute_bar(bar, NULL, NULL, target, action,
506 : : token, offset, size, width);
507 [ # # ]: 0 : if (ret != 0)
508 : 0 : continue;
509 : :
510 [ # # ]: 0 : if (!bar->lock)
511 : 0 : return n;
512 : : }
513 : :
514 : : return -EAGAIN;
515 : : }
516 : :
517 : : static int
518 : 0 : nfp_alloc_bar(struct nfp_pcie_user *nfp,
519 : : struct nfp6000_area_priv *priv)
520 : : {
521 : : int ret;
522 : : int bar_num;
523 : 0 : size_t size = priv->size;
524 : 0 : int token = priv->token;
525 : 0 : int target = priv->target;
526 : 0 : int action = priv->action;
527 : 0 : int width = priv->width.bar;
528 : 0 : uint64_t offset = priv->offset;
529 : :
530 : : /* Bar size should small than 16MB */
531 [ # # ]: 0 : if (size > (1 << 24))
532 : : return -EINVAL;
533 : :
534 : 0 : bar_num = find_matching_bar(nfp, target, action, token,
535 : : offset, size, width);
536 [ # # ]: 0 : if (bar_num >= 0) {
537 : : /* Found a perfect match. */
538 : 0 : nfp->bar[bar_num].lock = true;
539 : 0 : return bar_num;
540 : : }
541 : :
542 : 0 : bar_num = find_unused_bar_noblock(nfp, target, action, token,
543 : : offset, size, width);
544 [ # # ]: 0 : if (bar_num < 0)
545 : : return bar_num;
546 : :
547 : 0 : nfp->bar[bar_num].lock = true;
548 : 0 : ret = nfp_reconfigure_bar(nfp, &nfp->bar[bar_num],
549 : : target, action, token, offset, size, width);
550 [ # # ]: 0 : if (ret < 0) {
551 : 0 : nfp->bar[bar_num].lock = false;
552 : 0 : return ret;
553 : : }
554 : :
555 : : return bar_num;
556 : : }
557 : :
558 : : static void
559 : : nfp_disable_bars(struct nfp_pcie_user *nfp)
560 : : {
561 : : uint32_t i;
562 : : struct nfp_bar *bar;
563 : :
564 [ # # ]: 0 : for (i = 0; i < nfp->bars; i++) {
565 : : bar = &nfp->bar[i];
566 [ # # ]: 0 : if (bar->iomem != NULL) {
567 : 0 : bar->iomem = NULL;
568 : 0 : bar->lock = false;
569 : : }
570 : : }
571 : : }
572 : :
573 : : static int
574 : 0 : nfp6000_area_init(struct nfp_cpp_area *area,
575 : : uint32_t dest,
576 : : uint64_t address,
577 : : size_t size)
578 : : {
579 : : int pp;
580 : : int ret = 0;
581 : : uint32_t token = NFP_CPP_ID_TOKEN_of(dest);
582 : 0 : uint32_t target = NFP_CPP_ID_TARGET_of(dest);
583 : : uint32_t action = NFP_CPP_ID_ACTION_of(dest);
584 : 0 : struct nfp6000_area_priv *priv = nfp_cpp_area_priv(area);
585 : :
586 : 0 : pp = nfp_target_pushpull(NFP_CPP_ID(target, action, token), address);
587 [ # # ]: 0 : if (pp < 0)
588 : : return pp;
589 : :
590 : 0 : priv->width.read = PUSH_WIDTH(pp);
591 [ # # ]: 0 : priv->width.write = PULL_WIDTH(pp);
592 : :
593 [ # # # # ]: 0 : if (priv->width.read > 0 &&
594 [ # # ]: 0 : priv->width.write > 0 &&
595 : : priv->width.read != priv->width.write)
596 : : return -EINVAL;
597 : :
598 [ # # ]: 0 : if (priv->width.read > 0)
599 : 0 : priv->width.bar = priv->width.read;
600 : : else
601 : 0 : priv->width.bar = priv->width.write;
602 : :
603 : 0 : priv->bar = NULL;
604 : :
605 : 0 : priv->target = target;
606 : 0 : priv->action = action;
607 : 0 : priv->token = token;
608 : 0 : priv->offset = address;
609 : 0 : priv->size = size;
610 : :
611 : 0 : return ret;
612 : : }
613 : :
614 : : static int
615 : 0 : nfp6000_area_acquire(struct nfp_cpp_area *area)
616 : : {
617 : : int bar_num;
618 : 0 : struct nfp6000_area_priv *priv = nfp_cpp_area_priv(area);
619 : 0 : struct nfp_pcie_user *nfp = nfp_cpp_priv(nfp_cpp_area_cpp(area));
620 : :
621 : : /* Already allocated. */
622 [ # # ]: 0 : if (priv->bar != NULL)
623 : : return 0;
624 : :
625 : 0 : bar_num = nfp_alloc_bar(nfp, priv);
626 [ # # ]: 0 : if (bar_num < 0) {
627 : 0 : PMD_DRV_LOG(ERR, "Failed to allocate bar %d:%d:%d:%#lx: %d",
628 : : priv->target, priv->action, priv->token,
629 : : priv->offset, bar_num);
630 : 0 : return bar_num;
631 : : }
632 : :
633 : 0 : priv->bar = &nfp->bar[bar_num];
634 : :
635 : : /* Calculate offset into BAR. */
636 [ # # ]: 0 : if (nfp_bar_maptype(priv->bar) ==
637 : : NFP_PCIE_BAR_PCIE2CPP_MAPTYPE_GENERAL) {
638 : 0 : priv->bar_offset = priv->offset &
639 : 0 : (NFP_PCIE_P2C_GENERAL_SIZE(priv->bar) - 1);
640 : 0 : priv->bar_offset += NFP_PCIE_P2C_GENERAL_TARGET_OFFSET(priv->bar,
641 : : priv->target);
642 : 0 : priv->bar_offset += NFP_PCIE_P2C_GENERAL_TOKEN_OFFSET(priv->bar,
643 : : priv->token);
644 : : } else {
645 : 0 : priv->bar_offset = priv->offset & priv->bar->mask;
646 : : }
647 : :
648 : : /* Must have been too big. Sub-allocate. */
649 [ # # ]: 0 : if (priv->bar->iomem == NULL)
650 : : return -ENOMEM;
651 : :
652 : 0 : priv->iomem = priv->bar->iomem + priv->bar_offset;
653 : :
654 : 0 : return 0;
655 : : }
656 : :
657 : : static void
658 : 0 : nfp6000_area_release(struct nfp_cpp_area *area)
659 : : {
660 : 0 : struct nfp6000_area_priv *priv = nfp_cpp_area_priv(area);
661 : :
662 : 0 : priv->bar->lock = false;
663 : 0 : priv->bar = NULL;
664 : 0 : priv->iomem = NULL;
665 : 0 : }
666 : :
667 : : static void *
668 : 0 : nfp6000_area_iomem(struct nfp_cpp_area *area)
669 : : {
670 : 0 : struct nfp6000_area_priv *priv = nfp_cpp_area_priv(area);
671 : 0 : return priv->iomem;
672 : : }
673 : :
674 : : static int
675 : 0 : nfp6000_area_read(struct nfp_cpp_area *area,
676 : : void *address,
677 : : uint32_t offset,
678 : : size_t length)
679 : : {
680 : : int ret;
681 : : size_t n;
682 : : int width;
683 : : uint32_t *wrptr32 = address;
684 : : uint64_t *wrptr64 = address;
685 : : struct nfp6000_area_priv *priv;
686 : : const volatile uint32_t *rdptr32;
687 : : const volatile uint64_t *rdptr64;
688 : :
689 : 0 : priv = nfp_cpp_area_priv(area);
690 : 0 : rdptr64 = (uint64_t *)(priv->iomem + offset);
691 : : rdptr32 = (uint32_t *)(priv->iomem + offset);
692 : :
693 [ # # ]: 0 : if (offset + length > priv->size)
694 : : return -EFAULT;
695 : :
696 : 0 : width = priv->width.read;
697 [ # # ]: 0 : if (width <= 0)
698 : : return -EINVAL;
699 : :
700 : : /* MU reads via a PCIe2CPP BAR support 32bit (and other) lengths */
701 [ # # ]: 0 : if (priv->target == (NFP_CPP_TARGET_MU & NFP_CPP_TARGET_ID_MASK) &&
702 [ # # ]: 0 : priv->action == NFP_CPP_ACTION_RW &&
703 [ # # ]: 0 : (offset % sizeof(uint64_t) == 4 ||
704 [ # # ]: 0 : length % sizeof(uint64_t) == 4))
705 : : width = TARGET_WIDTH_32;
706 : :
707 : : /* Unaligned? Translate to an explicit access */
708 [ # # ]: 0 : if (((priv->offset + offset) & (width - 1)) != 0) {
709 : 0 : PMD_DRV_LOG(ERR, "aread_read unaligned!!!");
710 : 0 : return -EINVAL;
711 : : }
712 : :
713 [ # # ]: 0 : if (priv->bar == NULL)
714 : : return -EFAULT;
715 : :
716 [ # # # ]: 0 : switch (width) {
717 : 0 : case TARGET_WIDTH_32:
718 [ # # ]: 0 : if (offset % sizeof(uint32_t) != 0 ||
719 [ # # ]: 0 : length % sizeof(uint32_t) != 0)
720 : : return -EINVAL;
721 : :
722 [ # # ]: 0 : for (n = 0; n < length; n += sizeof(uint32_t)) {
723 : 0 : *wrptr32 = *rdptr32;
724 : 0 : wrptr32++;
725 : 0 : rdptr32++;
726 : : }
727 : :
728 : 0 : ret = n;
729 : 0 : break;
730 : 0 : case TARGET_WIDTH_64:
731 [ # # ]: 0 : if (offset % sizeof(uint64_t) != 0 ||
732 [ # # ]: 0 : length % sizeof(uint64_t) != 0)
733 : : return -EINVAL;
734 : :
735 [ # # ]: 0 : for (n = 0; n < length; n += sizeof(uint64_t)) {
736 : 0 : *wrptr64 = *rdptr64;
737 : 0 : wrptr64++;
738 : 0 : rdptr64++;
739 : : }
740 : :
741 : 0 : ret = n;
742 : 0 : break;
743 : : default:
744 : : return -EINVAL;
745 : : }
746 : :
747 : : return ret;
748 : : }
749 : :
750 : : static int
751 : 0 : nfp6000_area_write(struct nfp_cpp_area *area,
752 : : const void *address,
753 : : uint32_t offset,
754 : : size_t length)
755 : : {
756 : : int ret;
757 : : size_t n;
758 : : int width;
759 : : uint32_t *wrptr32;
760 : : uint64_t *wrptr64;
761 : : struct nfp6000_area_priv *priv;
762 : : const uint32_t *rdptr32 = address;
763 : : const uint64_t *rdptr64 = address;
764 : :
765 : 0 : priv = nfp_cpp_area_priv(area);
766 : 0 : wrptr64 = (uint64_t *)(priv->iomem + offset);
767 : : wrptr32 = (uint32_t *)(priv->iomem + offset);
768 : :
769 [ # # ]: 0 : if (offset + length > priv->size)
770 : : return -EFAULT;
771 : :
772 : 0 : width = priv->width.write;
773 [ # # ]: 0 : if (width <= 0)
774 : : return -EINVAL;
775 : :
776 : : /* MU reads via a PCIe2CPP BAR support 32bit (and other) lengths */
777 [ # # ]: 0 : if (priv->target == (NFP_CPP_TARGET_MU & NFP_CPP_TARGET_ID_MASK) &&
778 [ # # ]: 0 : priv->action == NFP_CPP_ACTION_RW &&
779 [ # # ]: 0 : (offset % sizeof(uint64_t) == 4 ||
780 [ # # ]: 0 : length % sizeof(uint64_t) == 4))
781 : : width = TARGET_WIDTH_32;
782 : :
783 : : /* Unaligned? Translate to an explicit access */
784 [ # # ]: 0 : if (((priv->offset + offset) & (width - 1)) != 0)
785 : : return -EINVAL;
786 : :
787 [ # # ]: 0 : if (priv->bar == NULL)
788 : : return -EFAULT;
789 : :
790 [ # # # ]: 0 : switch (width) {
791 : 0 : case TARGET_WIDTH_32:
792 [ # # ]: 0 : if (offset % sizeof(uint32_t) != 0 ||
793 [ # # ]: 0 : length % sizeof(uint32_t) != 0)
794 : : return -EINVAL;
795 : :
796 [ # # ]: 0 : for (n = 0; n < length; n += sizeof(uint32_t)) {
797 : 0 : *wrptr32 = *rdptr32;
798 : 0 : wrptr32++;
799 : 0 : rdptr32++;
800 : : }
801 : :
802 : 0 : ret = n;
803 : 0 : break;
804 : 0 : case TARGET_WIDTH_64:
805 [ # # ]: 0 : if (offset % sizeof(uint64_t) != 0 ||
806 [ # # ]: 0 : length % sizeof(uint64_t) != 0)
807 : : return -EINVAL;
808 : :
809 [ # # ]: 0 : for (n = 0; n < length; n += sizeof(uint64_t)) {
810 : 0 : *wrptr64 = *rdptr64;
811 : 0 : wrptr64++;
812 : 0 : rdptr64++;
813 : : }
814 : :
815 : 0 : ret = n;
816 : 0 : break;
817 : : default:
818 : : return -EINVAL;
819 : : }
820 : :
821 : : return ret;
822 : : }
823 : :
824 : : static int
825 : 0 : nfp_acquire_process_lock(struct nfp_pcie_user *desc)
826 : : {
827 : : int rc;
828 : : struct flock lock;
829 : : char lockname[30];
830 : :
831 : : memset(&lock, 0, sizeof(lock));
832 : :
833 : 0 : snprintf(lockname, sizeof(lockname), "/var/lock/nfp_%s",
834 : 0 : desc->pci_dev->device.name);
835 : 0 : desc->lock = open(lockname, O_RDWR | O_CREAT, 0666);
836 [ # # ]: 0 : if (desc->lock < 0)
837 : : return desc->lock;
838 : :
839 : 0 : lock.l_type = F_WRLCK;
840 : 0 : lock.l_whence = SEEK_SET;
841 : : rc = -1;
842 [ # # ]: 0 : while (rc != 0) {
843 : 0 : rc = fcntl(desc->lock, F_SETLKW, &lock);
844 [ # # ]: 0 : if (rc < 0) {
845 [ # # ]: 0 : if (errno != EAGAIN && errno != EACCES) {
846 : 0 : close(desc->lock);
847 : 0 : return rc;
848 : : }
849 : : }
850 : : }
851 : :
852 : : return 0;
853 : : }
854 : :
855 : : static int
856 : 0 : nfp6000_get_dsn(struct rte_pci_device *pci_dev,
857 : : uint64_t *dsn)
858 : : {
859 : : off_t pos;
860 : : size_t len;
861 : 0 : uint64_t tmp = 0;
862 : :
863 : 0 : pos = rte_pci_find_ext_capability(pci_dev, RTE_PCI_EXT_CAP_ID_DSN);
864 [ # # ]: 0 : if (pos <= 0) {
865 : 0 : PMD_DRV_LOG(ERR, "PCI_EXT_CAP_ID_DSN not found");
866 : 0 : return -ENODEV;
867 : : }
868 : :
869 : 0 : pos += 4;
870 : : len = sizeof(tmp);
871 : :
872 [ # # ]: 0 : if (rte_pci_read_config(pci_dev, &tmp, len, pos) < 0) {
873 : 0 : PMD_DRV_LOG(ERR, "nfp get device serial number failed");
874 : 0 : return -ENOENT;
875 : : }
876 : :
877 : 0 : *dsn = tmp;
878 : :
879 : 0 : return 0;
880 : : }
881 : :
882 : : static int
883 : 0 : nfp6000_get_interface(struct rte_pci_device *dev,
884 : : uint16_t *interface)
885 : : {
886 : : int ret;
887 : 0 : uint64_t dsn = 0;
888 : :
889 : 0 : ret = nfp6000_get_dsn(dev, &dsn);
890 [ # # # # ]: 0 : if (ret != 0)
891 : : return ret;
892 : :
893 : 0 : *interface = dsn & 0xffff;
894 : :
895 : 0 : return 0;
896 : : }
897 : :
898 : : static int
899 : 0 : nfp6000_get_serial(struct rte_pci_device *dev,
900 : : uint8_t *serial,
901 : : size_t length)
902 : : {
903 : : int ret;
904 : 0 : uint64_t dsn = 0;
905 : :
906 [ # # ]: 0 : if (length < NFP_SERIAL_LEN)
907 : : return -ENOMEM;
908 : :
909 : 0 : ret = nfp6000_get_dsn(dev, &dsn);
910 [ # # ]: 0 : if (ret != 0)
911 : : return ret;
912 : :
913 : 0 : serial[0] = (dsn >> 56) & 0xff;
914 : 0 : serial[1] = (dsn >> 48) & 0xff;
915 : 0 : serial[2] = (dsn >> 40) & 0xff;
916 : 0 : serial[3] = (dsn >> 32) & 0xff;
917 : 0 : serial[4] = (dsn >> 24) & 0xff;
918 : 0 : serial[5] = (dsn >> 16) & 0xff;
919 : :
920 : 0 : return 0;
921 : : }
922 : :
923 : : static int
924 : 0 : nfp6000_init(struct nfp_cpp *cpp)
925 : : {
926 : : int ret = 0;
927 : 0 : struct nfp_pcie_user *desc = nfp_cpp_priv(cpp);
928 : :
929 [ # # # # ]: 0 : if (rte_eal_process_type() == RTE_PROC_PRIMARY &&
930 : 0 : nfp_cpp_driver_need_lock(cpp)) {
931 : 0 : ret = nfp_acquire_process_lock(desc);
932 [ # # ]: 0 : if (ret != 0)
933 : : return -1;
934 : : }
935 : :
936 : 0 : ret = nfp_enable_bars(desc);
937 [ # # ]: 0 : if (ret != 0) {
938 : 0 : PMD_DRV_LOG(ERR, "Enable bars failed");
939 : 0 : return -1;
940 : : }
941 : :
942 : : return 0;
943 : : }
944 : :
945 : : static void
946 : 0 : nfp6000_free(struct nfp_cpp *cpp)
947 : : {
948 : 0 : struct nfp_pcie_user *desc = nfp_cpp_priv(cpp);
949 : :
950 : : nfp_disable_bars(desc);
951 [ # # ]: 0 : if (nfp_cpp_driver_need_lock(cpp))
952 : 0 : close(desc->lock);
953 : 0 : free(desc);
954 : 0 : }
955 : :
956 : : static const struct nfp_cpp_operations nfp6000_pcie_ops = {
957 : : .init = nfp6000_init,
958 : : .free = nfp6000_free,
959 : :
960 : : .area_priv_size = sizeof(struct nfp6000_area_priv),
961 : :
962 : : .get_interface = nfp6000_get_interface,
963 : : .get_serial = nfp6000_get_serial,
964 : :
965 : : .area_init = nfp6000_area_init,
966 : : .area_acquire = nfp6000_area_acquire,
967 : : .area_release = nfp6000_area_release,
968 : : .area_read = nfp6000_area_read,
969 : : .area_write = nfp6000_area_write,
970 : : .area_iomem = nfp6000_area_iomem,
971 : : };
972 : :
973 : : const struct
974 : 0 : nfp_cpp_operations *nfp_cpp_transport_operations(void)
975 : : {
976 : 0 : return &nfp6000_pcie_ops;
977 : : }
978 : :
979 : : /**
980 : : * Build a NFP CPP bus from a NFP6000 PCI device
981 : : *
982 : : * @param pdev
983 : : * NFP6000 PCI device
984 : : * @param driver_lock_needed
985 : : * driver lock flag
986 : : *
987 : : * @return
988 : : * NFP CPP handle or NULL
989 : : */
990 : : struct nfp_cpp *
991 : 0 : nfp_cpp_from_nfp6000_pcie(struct rte_pci_device *pci_dev,
992 : : const struct nfp_dev_info *dev_info,
993 : : bool driver_lock_needed)
994 : : {
995 : : int ret;
996 : : struct nfp_cpp *cpp;
997 : : uint16_t interface = 0;
998 : : struct nfp_pcie_user *nfp;
999 : :
1000 : 0 : nfp = malloc(sizeof(*nfp));
1001 [ # # ]: 0 : if (nfp == NULL)
1002 : : return NULL;
1003 : :
1004 : : memset(nfp, 0, sizeof(*nfp));
1005 : 0 : nfp->pci_dev = pci_dev;
1006 : 0 : nfp->dev_info = dev_info;
1007 : :
1008 : : ret = nfp6000_get_interface(pci_dev, &interface);
1009 : : if (ret != 0) {
1010 : 0 : PMD_DRV_LOG(ERR, "Get interface failed.");
1011 : 0 : free(nfp);
1012 : 0 : return NULL;
1013 : : }
1014 : :
1015 [ # # ]: 0 : if (NFP_CPP_INTERFACE_TYPE_of(interface) != NFP_CPP_INTERFACE_TYPE_PCI) {
1016 : 0 : PMD_DRV_LOG(ERR, "Interface type is not right.");
1017 : 0 : free(nfp);
1018 : 0 : return NULL;
1019 : : }
1020 : :
1021 [ # # ]: 0 : if (NFP_CPP_INTERFACE_CHANNEL_of(interface) !=
1022 : : NFP_CPP_INTERFACE_CHANNEL_PEROPENER) {
1023 : 0 : PMD_DRV_LOG(ERR, "Interface channel is not right");
1024 : 0 : free(nfp);
1025 : 0 : return NULL;
1026 : : }
1027 : :
1028 : : /* Probe for all the common NFP devices */
1029 : 0 : cpp = nfp_cpp_from_device_name(pci_dev, nfp, driver_lock_needed);
1030 [ # # ]: 0 : if (cpp == NULL) {
1031 : 0 : PMD_DRV_LOG(ERR, "Get cpp from operation failed");
1032 : 0 : free(nfp);
1033 : 0 : return NULL;
1034 : : }
1035 : :
1036 : : return cpp;
1037 : : }
|