dpdk/drivers/net/octeontx/base/octeontx_pkovf.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright(c) 2017 Cavium, Inc
   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 * Open a PKO DQ.
  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        /* Set the register to return descriptor (packet) count as DEPTH */
  96        /* KIND=1, NCB_QUERY_RSP=0 */
  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        /* PKO_DQOP_E::OPEN */
 104        if (((rtn >> PKO_DQ_OP_BIT) & 0x3) != 0x1)
 105                return -EIO;
 106
 107        switch (rtn >> PKO_DQ_STATUS_BIT) {
 108        case 0xC:       /* DQALREADYCREATED */
 109        case 0x0:       /* PASS */
 110                break;
 111        default:
 112                return -EIO;
 113        }
 114
 115        /* DRAIN=0, DRAIN_NULL_LINK=0, SW_XOFF=0 */
 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 * Close a PKO DQ
 123 * Flush all packets pending.
 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        /* PKO_DQOP_E::CLOSE */
 144        if (((rtn >> PKO_DQ_OP_BIT) & 0x3) != 0x2)
 145                return -EIO;
 146
 147        switch (rtn >> PKO_DQ_STATUS_BIT) {
 148        case 0xD:       /* DQNOTCREATED */
 149        case 0x0:       /* PASS */
 150                break;
 151        default:
 152                return -EIO;
 153        }
 154
 155        res = rtn & ((1ull << PKO_DQ_OP_BIT) - 1); /* DEPTH */
 156        return res;
 157}
 158
 159/* Flush all packets pending on a DQ */
 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         /* DRAIN=1, DRAIN_NULL_LINK=0, SW_XOFF=1 */
 173         octeontx_write64(0x3, vf_bar0 + PKO_VF_DQ_SW_XOFF(gdq));
 174        /* Wait until buffers leave DQs */
 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        /* DRAIN=0, DRAIN_NULL_LINK=0, SW_XOFF=0 */
 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        /* Configure Flow-Control feature for all DQs of open VFs */
 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 |=                  /* BASE */
 525                    (0x2 << 3) |        /* HYST_BITS */
 526                    (((PKO_DQ_FC_STRIDE == PKO_DQ_FC_STRIDE_16) ? 1 : 0) << 2) |
 527                    (0x1 << 0);         /* ENABLE */
 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/* PKOVF pcie device*/
 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        /* For secondary processes, the primary has done all the work */
 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        /* get vfid and domain */
 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