1
2
3
4
5#include <stdbool.h>
6#include <string.h>
7#include <stdio.h>
8
9#include <rte_eal.h>
10#include <rte_cycles.h>
11#include <rte_malloc.h>
12#include <rte_memory.h>
13#include <rte_bus_pci.h>
14#include <rte_spinlock.h>
15
16#include "../octeontx_logs.h"
17#include "octeontx_io.h"
18#include "octeontx_pkovf.h"
19
20struct octeontx_pko_iomem {
21 uint8_t *va;
22 rte_iova_t iova;
23 size_t size;
24};
25
26#define PKO_IOMEM_NULL (struct octeontx_pko_iomem){0, 0, 0}
27#define PKO_VALID 0x1
28#define PKO_INUSE 0x2
29
30struct octeontx_pko_fc_ctl_s {
31 int64_t buf_cnt;
32 int64_t padding[(PKO_DQ_FC_STRIDE / 8) - 1];
33};
34
35struct octeontx_pkovf {
36 uint8_t *bar0;
37 uint8_t *bar2;
38 uint8_t status;
39 uint16_t domain;
40 uint16_t vfid;
41};
42
43struct octeontx_pko_vf_ctl_s {
44 rte_spinlock_t lock;
45 uint16_t global_domain;
46 struct octeontx_pko_iomem fc_iomem;
47 struct octeontx_pko_fc_ctl_s *fc_ctl;
48 struct octeontx_pkovf pko[PKO_VF_MAX];
49 struct {
50 uint64_t chanid;
51 } dq_map[PKO_VF_MAX * PKO_VF_NUM_DQ];
52};
53
54static struct octeontx_pko_vf_ctl_s pko_vf_ctl;
55
56static void *
57octeontx_pko_dq_vf_bar0(uint16_t txq)
58{
59 int vf_ix;
60
61 vf_ix = txq / PKO_VF_NUM_DQ;
62 return pko_vf_ctl.pko[vf_ix].bar0;
63}
64
65static int
66octeontx_pko_dq_gdq(uint16_t txq)
67{
68 return txq % PKO_VF_NUM_DQ;
69}
70
71
72
73
74static inline
75int octeontx_pko_dq_open(uint16_t txq)
76{
77 unsigned int reg_off;
78 uint8_t *vf_bar0;
79 uint64_t rtn;
80 int gdq;
81
82 vf_bar0 = octeontx_pko_dq_vf_bar0(txq);
83 gdq = octeontx_pko_dq_gdq(txq);
84
85 if (unlikely(gdq < 0 || vf_bar0 == NULL))
86 return -EINVAL;
87 *(volatile int64_t*)(pko_vf_ctl.fc_ctl + txq) =
88 PKO_DQ_FC_DEPTH_PAGES - PKO_DQ_FC_SKID;
89
90 rte_wmb();
91
92 octeontx_write64(PKO_DQ_FC_DEPTH_PAGES,
93 vf_bar0 + PKO_VF_DQ_FC_STATUS(gdq));
94
95
96
97 octeontx_write64(1ull << PKO_DQ_KIND_BIT,
98 vf_bar0 + PKO_VF_DQ_WM_CTL(gdq));
99 reg_off = PKO_VF_DQ_OP_OPEN(gdq);
100
101 rtn = octeontx_reg_ldadd_u64(vf_bar0 + reg_off, 0);
102
103
104 if (((rtn >> PKO_DQ_OP_BIT) & 0x3) != 0x1)
105 return -EIO;
106
107 switch (rtn >> PKO_DQ_STATUS_BIT) {
108 case 0xC:
109 case 0x0:
110 break;
111 default:
112 return -EIO;
113 }
114
115
116 octeontx_write64(0, vf_bar0 + PKO_VF_DQ_SW_XOFF(gdq));
117
118 return rtn & ((1ull << PKO_DQ_OP_BIT) - 1);
119}
120
121
122
123
124
125static inline
126int octeontx_pko_dq_close(uint16_t txq)
127{
128 unsigned int reg_off;
129 uint8_t *vf_bar0;
130 uint64_t rtn;
131 int res;
132
133 vf_bar0 = octeontx_pko_dq_vf_bar0(txq);
134 res = octeontx_pko_dq_gdq(txq);
135
136 if (unlikely(res < 0 || vf_bar0 == NULL))
137 return -EINVAL;
138
139 reg_off = PKO_VF_DQ_OP_CLOSE(res);
140
141 rtn = octeontx_reg_ldadd_u64(vf_bar0 + reg_off, 0);
142
143
144 if (((rtn >> PKO_DQ_OP_BIT) & 0x3) != 0x2)
145 return -EIO;
146
147 switch (rtn >> PKO_DQ_STATUS_BIT) {
148 case 0xD:
149 case 0x0:
150 break;
151 default:
152 return -EIO;
153 }
154
155 res = rtn & ((1ull << PKO_DQ_OP_BIT) - 1);
156 return res;
157}
158
159
160static inline
161int octeontx_pko_dq_drain(uint16_t txq)
162{
163 unsigned int gdq;
164 uint8_t *vf_bar0;
165 uint64_t reg;
166 int res, timo = PKO_DQ_DRAIN_TO;
167
168 vf_bar0 = octeontx_pko_dq_vf_bar0(txq);
169 res = octeontx_pko_dq_gdq(txq);
170 gdq = res;
171
172
173 octeontx_write64(0x3, vf_bar0 + PKO_VF_DQ_SW_XOFF(gdq));
174
175 reg = octeontx_read64(vf_bar0 + PKO_VF_DQ_WM_CNT(gdq));
176 while (reg && timo > 0) {
177 rte_delay_us(100);
178 timo--;
179 reg = octeontx_read64(vf_bar0 + PKO_VF_DQ_WM_CNT(gdq));
180 }
181
182 octeontx_write64(0, vf_bar0 + PKO_VF_DQ_SW_XOFF(gdq));
183
184 return reg;
185}
186
187static inline int
188octeontx_pko_dq_range_lookup(struct octeontx_pko_vf_ctl_s *ctl, uint64_t chanid,
189 unsigned int dq_num, unsigned int dq_from)
190{
191 unsigned int dq, dq_cnt;
192 unsigned int dq_base;
193
194 dq_cnt = 0;
195 dq = dq_from;
196 while (dq < RTE_DIM(ctl->dq_map)) {
197 dq_base = dq;
198 dq_cnt = 0;
199 while (ctl->dq_map[dq].chanid == ~chanid &&
200 dq < RTE_DIM(ctl->dq_map)) {
201 dq_cnt++;
202 if (dq_cnt == dq_num)
203 return dq_base;
204 dq++;
205 }
206 dq++;
207 }
208 return -1;
209}
210
211static inline void
212octeontx_pko_dq_range_assign(struct octeontx_pko_vf_ctl_s *ctl, uint64_t chanid,
213 unsigned int dq_base, unsigned int dq_num)
214{
215 unsigned int dq, dq_cnt;
216
217 dq_cnt = 0;
218 while (dq_cnt < dq_num) {
219 dq = dq_base + dq_cnt;
220
221 octeontx_log_dbg("DQ# %u assigned to CHAN# %" PRIx64 "", dq,
222 chanid);
223
224 ctl->dq_map[dq].chanid = ~chanid;
225 dq_cnt++;
226 }
227}
228
229static inline int
230octeontx_pko_dq_claim(struct octeontx_pko_vf_ctl_s *ctl, unsigned int dq_base,
231 unsigned int dq_num, uint64_t chanid)
232{
233 const uint64_t null_chanid = ~0ull;
234 int dq;
235
236 rte_spinlock_lock(&ctl->lock);
237
238 dq = octeontx_pko_dq_range_lookup(ctl, null_chanid, dq_num, dq_base);
239 if (dq < 0 || (unsigned int)dq != dq_base) {
240 rte_spinlock_unlock(&ctl->lock);
241 return -1;
242 }
243 octeontx_pko_dq_range_assign(ctl, chanid, dq_base, dq_num);
244
245 rte_spinlock_unlock(&ctl->lock);
246
247 return 0;
248}
249
250static inline int
251octeontx_pko_dq_free(struct octeontx_pko_vf_ctl_s *ctl, uint64_t chanid)
252{
253 const uint64_t null_chanid = ~0ull;
254 unsigned int dq = 0, dq_cnt = 0;
255
256 rte_spinlock_lock(&ctl->lock);
257 while (dq < RTE_DIM(ctl->dq_map)) {
258 if (ctl->dq_map[dq].chanid == ~chanid) {
259 ctl->dq_map[dq].chanid = ~null_chanid;
260 dq_cnt++;
261 }
262 dq++;
263 }
264 rte_spinlock_unlock(&ctl->lock);
265
266 return dq_cnt > 0 ? 0 : -EINVAL;
267}
268
269int
270octeontx_pko_channel_open(int dq_base, int dq_num, int chanid)
271{
272 struct octeontx_pko_vf_ctl_s *ctl = &pko_vf_ctl;
273 int res;
274
275 res = octeontx_pko_dq_claim(ctl, dq_base, dq_num, chanid);
276 if (res < 0)
277 return -1;
278
279 return 0;
280}
281
282int
283octeontx_pko_channel_close(int chanid)
284{
285 struct octeontx_pko_vf_ctl_s *ctl = &pko_vf_ctl;
286 int res;
287
288 res = octeontx_pko_dq_free(ctl, chanid);
289 if (res < 0)
290 return -1;
291
292 return 0;
293}
294
295static inline int
296octeontx_pko_chan_start(struct octeontx_pko_vf_ctl_s *ctl, uint64_t chanid)
297{
298 unsigned int dq_vf;
299 unsigned int dq, dq_cnt;
300
301 dq_cnt = 0;
302 dq = 0;
303 while (dq < RTE_DIM(ctl->dq_map)) {
304 dq_vf = dq / PKO_VF_NUM_DQ;
305
306 if (!ctl->pko[dq_vf].bar0) {
307 dq += PKO_VF_NUM_DQ;
308 continue;
309 }
310
311 if (ctl->dq_map[dq].chanid != ~chanid) {
312 dq++;
313 continue;
314 }
315
316 if (octeontx_pko_dq_open(dq) < 0)
317 break;
318
319 dq_cnt++;
320 dq++;
321 }
322
323 return dq_cnt;
324}
325
326int
327octeontx_pko_channel_start(int chanid)
328{
329 struct octeontx_pko_vf_ctl_s *ctl = &pko_vf_ctl;
330 int dq_cnt;
331
332 dq_cnt = octeontx_pko_chan_start(ctl, chanid);
333 if (dq_cnt < 0)
334 return -1;
335
336 return dq_cnt;
337}
338
339static inline int
340octeontx_pko_chan_stop(struct octeontx_pko_vf_ctl_s *ctl, uint64_t chanid)
341{
342 unsigned int dq, dq_cnt, dq_vf;
343 int res;
344
345 dq_cnt = 0;
346 dq = 0;
347 while (dq < RTE_DIM(ctl->dq_map)) {
348 dq_vf = dq / PKO_VF_NUM_DQ;
349
350 if (!ctl->pko[dq_vf].bar0) {
351 dq += PKO_VF_NUM_DQ;
352 continue;
353 }
354
355 if (ctl->dq_map[dq].chanid != ~chanid) {
356 dq++;
357 continue;
358 }
359
360 res = octeontx_pko_dq_drain(dq);
361 if (res > 0)
362 octeontx_log_err("draining DQ%d, buffers left: %x",
363 dq, res);
364
365 res = octeontx_pko_dq_close(dq);
366 if (res < 0)
367 octeontx_log_err("closing DQ%d failed\n", dq);
368
369 dq_cnt++;
370 dq++;
371 }
372 return dq_cnt;
373}
374
375int
376octeontx_pko_channel_stop(int chanid)
377{
378 struct octeontx_pko_vf_ctl_s *ctl = &pko_vf_ctl;
379
380 octeontx_pko_chan_stop(ctl, chanid);
381 return 0;
382}
383
384static inline int
385octeontx_pko_channel_query(struct octeontx_pko_vf_ctl_s *ctl, uint64_t chanid,
386 void *out, size_t out_elem_size,
387 size_t dq_num, octeontx_pko_dq_getter_t getter)
388{
389 octeontx_dq_t curr;
390 unsigned int dq_vf;
391 unsigned int dq;
392
393 RTE_SET_USED(out_elem_size);
394 memset(&curr, 0, sizeof(octeontx_dq_t));
395
396 dq_vf = dq_num / PKO_VF_NUM_DQ;
397 dq = dq_num % PKO_VF_NUM_DQ;
398
399 if (!ctl->pko[dq_vf].bar0)
400 return -EINVAL;
401
402 if (ctl->dq_map[dq_num].chanid != ~chanid)
403 return -EINVAL;
404
405 uint8_t *iter = (uint8_t *)out;
406 curr.lmtline_va = ctl->pko[dq_vf].bar2;
407 curr.ioreg_va = (void *)((uintptr_t)ctl->pko[dq_vf].bar0
408 + PKO_VF_DQ_OP_SEND((dq), 0));
409 curr.fc_status_va = ctl->fc_ctl + dq_num;
410
411 octeontx_log_dbg("lmtline=%p ioreg_va=%p fc_status_va=%p",
412 curr.lmtline_va, curr.ioreg_va,
413 curr.fc_status_va);
414
415 getter(&curr, (void *)iter);
416 return 0;
417}
418
419int
420octeontx_pko_channel_query_dqs(int chanid, void *out, size_t out_elem_size,
421 size_t dq_num, octeontx_pko_dq_getter_t getter)
422{
423 struct octeontx_pko_vf_ctl_s *ctl = &pko_vf_ctl;
424 int dq_cnt;
425
426 dq_cnt = octeontx_pko_channel_query(ctl, chanid, out, out_elem_size,
427 dq_num, getter);
428 if (dq_cnt < 0)
429 return -1;
430
431 return dq_cnt;
432}
433
434int
435octeontx_pko_vf_count(void)
436{
437 uint16_t global_domain = octeontx_get_global_domain();
438 int vf_cnt;
439
440 pko_vf_ctl.global_domain = global_domain;
441 vf_cnt = 0;
442 while (pko_vf_ctl.pko[vf_cnt].bar0)
443 vf_cnt++;
444
445 return vf_cnt;
446}
447
448size_t
449octeontx_pko_get_vfid(void)
450{
451 size_t vf_cnt = octeontx_pko_vf_count();
452 size_t vf_idx;
453
454
455 for (vf_idx = 0; vf_idx < vf_cnt; vf_idx++) {
456 if (!(pko_vf_ctl.pko[vf_idx].status & PKO_VALID))
457 continue;
458 if (pko_vf_ctl.pko[vf_idx].status & PKO_INUSE)
459 continue;
460
461 pko_vf_ctl.pko[vf_idx].status |= PKO_INUSE;
462 return pko_vf_ctl.pko[vf_idx].vfid;
463 }
464
465 return SIZE_MAX;
466}
467
468int
469octeontx_pko_send_mtu(int port, int mtu)
470{
471 struct octeontx_mbox_hdr hdr;
472 int res;
473 mbox_pko_mtu_cfg_t cfg;
474
475 cfg.mtu = mtu;
476
477 hdr.coproc = OCTEONTX_PKO_COPROC;
478 hdr.msg = MBOX_PKO_MTU_CONFIG;
479 hdr.vfid = port;
480
481 res = octeontx_mbox_send(&hdr, &cfg, sizeof(mbox_pko_mtu_cfg_t),
482 NULL, 0);
483 if (res < 0)
484 return -EACCES;
485
486 return res;
487}
488
489int
490octeontx_pko_init_fc(const size_t pko_vf_count)
491{
492 int dq_ix;
493 uint64_t reg;
494 uint8_t *vf_bar0;
495 size_t vf_idx;
496 size_t fc_mem_size;
497
498 fc_mem_size = sizeof(struct octeontx_pko_fc_ctl_s) *
499 pko_vf_count * PKO_VF_NUM_DQ;
500
501 pko_vf_ctl.fc_iomem.va = rte_malloc(NULL, fc_mem_size, 128);
502 if (unlikely(!pko_vf_ctl.fc_iomem.va)) {
503 octeontx_log_err("fc_iomem: not enough memory");
504 return -ENOMEM;
505 }
506
507 pko_vf_ctl.fc_iomem.iova = rte_malloc_virt2iova((void *)
508 pko_vf_ctl.fc_iomem.va);
509 pko_vf_ctl.fc_iomem.size = fc_mem_size;
510
511 pko_vf_ctl.fc_ctl =
512 (struct octeontx_pko_fc_ctl_s *)pko_vf_ctl.fc_iomem.va;
513
514
515 for (vf_idx = 0; vf_idx < pko_vf_count; vf_idx++) {
516 if (pko_vf_ctl.pko[vf_idx].domain != pko_vf_ctl.global_domain)
517 continue;
518
519 dq_ix = pko_vf_ctl.pko[vf_idx].vfid * PKO_VF_NUM_DQ;
520 vf_bar0 = pko_vf_ctl.pko[vf_idx].bar0;
521
522 reg = (pko_vf_ctl.fc_iomem.iova +
523 (sizeof(struct octeontx_pko_fc_ctl_s) * dq_ix)) & ~0x7F;
524 reg |=
525 (0x2 << 3) |
526 (((PKO_DQ_FC_STRIDE == PKO_DQ_FC_STRIDE_16) ? 1 : 0) << 2) |
527 (0x1 << 0);
528
529 octeontx_write64(reg, vf_bar0 + PKO_VF_DQ_FC_CONFIG);
530 pko_vf_ctl.pko[vf_idx].status = PKO_VALID;
531
532 octeontx_log_dbg("PKO: bar0 %p VF_idx %d DQ_FC_CFG=%" PRIx64 "",
533 vf_bar0, (int)vf_idx, reg);
534 }
535 return 0;
536}
537
538void
539octeontx_pko_fc_free(void)
540{
541 rte_free(pko_vf_ctl.fc_iomem.va);
542}
543
544static void
545octeontx_pkovf_setup(void)
546{
547 static bool init_once;
548
549 if (!init_once) {
550 unsigned int i;
551
552 rte_spinlock_init(&pko_vf_ctl.lock);
553
554 pko_vf_ctl.fc_iomem = PKO_IOMEM_NULL;
555 pko_vf_ctl.fc_ctl = NULL;
556
557 for (i = 0; i < PKO_VF_MAX; i++) {
558 pko_vf_ctl.pko[i].bar0 = NULL;
559 pko_vf_ctl.pko[i].bar2 = NULL;
560 pko_vf_ctl.pko[i].domain = ~(uint16_t)0;
561 pko_vf_ctl.pko[i].vfid = ~(uint16_t)0;
562 }
563
564 for (i = 0; i < (PKO_VF_MAX * PKO_VF_NUM_DQ); i++)
565 pko_vf_ctl.dq_map[i].chanid = 0;
566
567 init_once = true;
568 }
569}
570
571
572static int
573pkovf_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
574{
575 uint64_t val;
576 uint16_t vfid;
577 uint16_t domain;
578 uint8_t *bar0;
579 uint8_t *bar2;
580 static uint8_t vf_cnt;
581 struct octeontx_pkovf *res;
582
583 RTE_SET_USED(pci_drv);
584
585
586 if (rte_eal_process_type() != RTE_PROC_PRIMARY)
587 return 0;
588
589 if (pci_dev->mem_resource[0].addr == NULL ||
590 pci_dev->mem_resource[2].addr == NULL) {
591 octeontx_log_err("Empty bars %p %p",
592 pci_dev->mem_resource[0].addr,
593 pci_dev->mem_resource[2].addr);
594 return -ENODEV;
595 }
596 bar0 = pci_dev->mem_resource[0].addr;
597 bar2 = pci_dev->mem_resource[2].addr;
598
599 octeontx_pkovf_setup();
600
601
602 val = octeontx_read64(bar0 + PKO_VF_DQ_FC_CONFIG);
603 domain = (val >> 7) & 0xffff;
604 vfid = (val >> 23) & 0xffff;
605
606 if (unlikely(vfid >= PKO_VF_MAX)) {
607 octeontx_log_err("pko: Invalid vfid %d", vfid);
608 return -EINVAL;
609 }
610
611 res = &pko_vf_ctl.pko[vf_cnt++];
612 res->vfid = vfid;
613 res->domain = domain;
614 res->bar0 = bar0;
615 res->bar2 = bar2;
616
617 octeontx_log_dbg("Domain=%d group=%d", res->domain, res->vfid);
618 return 0;
619}
620
621#define PCI_VENDOR_ID_CAVIUM 0x177D
622#define PCI_DEVICE_ID_OCTEONTX_PKO_VF 0xA049
623
624static const struct rte_pci_id pci_pkovf_map[] = {
625 {
626 RTE_PCI_DEVICE(PCI_VENDOR_ID_CAVIUM,
627 PCI_DEVICE_ID_OCTEONTX_PKO_VF)
628 },
629 {
630 .vendor_id = 0,
631 },
632};
633
634static struct rte_pci_driver pci_pkovf = {
635 .id_table = pci_pkovf_map,
636 .drv_flags = RTE_PCI_DRV_NEED_MAPPING,
637 .probe = pkovf_probe,
638};
639
640RTE_PMD_REGISTER_PCI(octeontx_pkovf, pci_pkovf);
641