1aaf4363eSJerin Jacob /* SPDX-License-Identifier: BSD-3-Clause 2aaf4363eSJerin Jacob * Copyright(c) 2017 Cavium, Inc 3445371e8SJerin Jacob */ 4aaf4363eSJerin Jacob 5445371e8SJerin Jacob #include <stdbool.h> 6445371e8SJerin Jacob #include <string.h> 7445371e8SJerin Jacob #include <stdio.h> 8445371e8SJerin Jacob 9445371e8SJerin Jacob #include <rte_eal.h> 10445371e8SJerin Jacob #include <rte_cycles.h> 11445371e8SJerin Jacob #include <rte_malloc.h> 12445371e8SJerin Jacob #include <rte_memory.h> 131f37cb2bSDavid Marchand #include <bus_pci_driver.h> 14445371e8SJerin Jacob #include <rte_spinlock.h> 15445371e8SJerin Jacob 16445371e8SJerin Jacob #include "../octeontx_logs.h" 17445371e8SJerin Jacob #include "octeontx_io.h" 18445371e8SJerin Jacob #include "octeontx_pkovf.h" 19445371e8SJerin Jacob 20445371e8SJerin Jacob struct octeontx_pko_iomem { 21445371e8SJerin Jacob uint8_t *va; 22df6e0a06SSantosh Shukla rte_iova_t iova; 23445371e8SJerin Jacob size_t size; 24445371e8SJerin Jacob }; 25445371e8SJerin Jacob 26445371e8SJerin Jacob #define PKO_IOMEM_NULL (struct octeontx_pko_iomem){0, 0, 0} 27a6d6f0afSPavan Nikhilesh #define PKO_VALID 0x1 28a6d6f0afSPavan Nikhilesh #define PKO_INUSE 0x2 29445371e8SJerin Jacob 30445371e8SJerin Jacob struct octeontx_pko_fc_ctl_s { 31445371e8SJerin Jacob int64_t buf_cnt; 32445371e8SJerin Jacob int64_t padding[(PKO_DQ_FC_STRIDE / 8) - 1]; 33445371e8SJerin Jacob }; 34445371e8SJerin Jacob 35445371e8SJerin Jacob struct octeontx_pkovf { 36445371e8SJerin Jacob uint8_t *bar0; 37445371e8SJerin Jacob uint8_t *bar2; 38a6d6f0afSPavan Nikhilesh uint8_t status; 39445371e8SJerin Jacob uint16_t domain; 40445371e8SJerin Jacob uint16_t vfid; 41445371e8SJerin Jacob }; 42445371e8SJerin Jacob 43445371e8SJerin Jacob struct octeontx_pko_vf_ctl_s { 44445371e8SJerin Jacob rte_spinlock_t lock; 45a6d6f0afSPavan Nikhilesh uint16_t global_domain; 46445371e8SJerin Jacob struct octeontx_pko_iomem fc_iomem; 47445371e8SJerin Jacob struct octeontx_pko_fc_ctl_s *fc_ctl; 48445371e8SJerin Jacob struct octeontx_pkovf pko[PKO_VF_MAX]; 49445371e8SJerin Jacob struct { 50445371e8SJerin Jacob uint64_t chanid; 51445371e8SJerin Jacob } dq_map[PKO_VF_MAX * PKO_VF_NUM_DQ]; 52445371e8SJerin Jacob }; 53445371e8SJerin Jacob 54445371e8SJerin Jacob static struct octeontx_pko_vf_ctl_s pko_vf_ctl; 55445371e8SJerin Jacob 56cad78ca2SJerin Jacob static void * 57cad78ca2SJerin Jacob octeontx_pko_dq_vf_bar0(uint16_t txq) 58cad78ca2SJerin Jacob { 59cad78ca2SJerin Jacob int vf_ix; 60cad78ca2SJerin Jacob 61cad78ca2SJerin Jacob vf_ix = txq / PKO_VF_NUM_DQ; 62cad78ca2SJerin Jacob return pko_vf_ctl.pko[vf_ix].bar0; 63cad78ca2SJerin Jacob } 64cad78ca2SJerin Jacob 65cad78ca2SJerin Jacob static int 66cad78ca2SJerin Jacob octeontx_pko_dq_gdq(uint16_t txq) 67cad78ca2SJerin Jacob { 68cad78ca2SJerin Jacob return txq % PKO_VF_NUM_DQ; 69cad78ca2SJerin Jacob } 70cad78ca2SJerin Jacob 71cad78ca2SJerin Jacob /** 72cad78ca2SJerin Jacob * Open a PKO DQ. 73cad78ca2SJerin Jacob */ 74cad78ca2SJerin Jacob static inline 75cad78ca2SJerin Jacob int octeontx_pko_dq_open(uint16_t txq) 76cad78ca2SJerin Jacob { 77cad78ca2SJerin Jacob unsigned int reg_off; 78cad78ca2SJerin Jacob uint8_t *vf_bar0; 79cad78ca2SJerin Jacob uint64_t rtn; 80cad78ca2SJerin Jacob int gdq; 81cad78ca2SJerin Jacob 82cad78ca2SJerin Jacob vf_bar0 = octeontx_pko_dq_vf_bar0(txq); 83cad78ca2SJerin Jacob gdq = octeontx_pko_dq_gdq(txq); 84cad78ca2SJerin Jacob 85cad78ca2SJerin Jacob if (unlikely(gdq < 0 || vf_bar0 == NULL)) 86cad78ca2SJerin Jacob return -EINVAL; 87cad78ca2SJerin Jacob *(volatile int64_t*)(pko_vf_ctl.fc_ctl + txq) = 88cad78ca2SJerin Jacob PKO_DQ_FC_DEPTH_PAGES - PKO_DQ_FC_SKID; 89cad78ca2SJerin Jacob 90cad78ca2SJerin Jacob rte_wmb(); 91cad78ca2SJerin Jacob 92cad78ca2SJerin Jacob octeontx_write64(PKO_DQ_FC_DEPTH_PAGES, 93cad78ca2SJerin Jacob vf_bar0 + PKO_VF_DQ_FC_STATUS(gdq)); 94cad78ca2SJerin Jacob 95cad78ca2SJerin Jacob /* Set the register to return descriptor (packet) count as DEPTH */ 96cad78ca2SJerin Jacob /* KIND=1, NCB_QUERY_RSP=0 */ 97cad78ca2SJerin Jacob octeontx_write64(1ull << PKO_DQ_KIND_BIT, 98cad78ca2SJerin Jacob vf_bar0 + PKO_VF_DQ_WM_CTL(gdq)); 99cad78ca2SJerin Jacob reg_off = PKO_VF_DQ_OP_OPEN(gdq); 100cad78ca2SJerin Jacob 101cad78ca2SJerin Jacob rtn = octeontx_reg_ldadd_u64(vf_bar0 + reg_off, 0); 102cad78ca2SJerin Jacob 103cad78ca2SJerin Jacob /* PKO_DQOP_E::OPEN */ 104cad78ca2SJerin Jacob if (((rtn >> PKO_DQ_OP_BIT) & 0x3) != 0x1) 105cad78ca2SJerin Jacob return -EIO; 106cad78ca2SJerin Jacob 107cad78ca2SJerin Jacob switch (rtn >> PKO_DQ_STATUS_BIT) { 108cad78ca2SJerin Jacob case 0xC: /* DQALREADYCREATED */ 109cad78ca2SJerin Jacob case 0x0: /* PASS */ 110cad78ca2SJerin Jacob break; 111cad78ca2SJerin Jacob default: 112cad78ca2SJerin Jacob return -EIO; 113cad78ca2SJerin Jacob } 114cad78ca2SJerin Jacob 115cad78ca2SJerin Jacob /* DRAIN=0, DRAIN_NULL_LINK=0, SW_XOFF=0 */ 116cad78ca2SJerin Jacob octeontx_write64(0, vf_bar0 + PKO_VF_DQ_SW_XOFF(gdq)); 117cad78ca2SJerin Jacob 118cad78ca2SJerin Jacob return rtn & ((1ull << PKO_DQ_OP_BIT) - 1); 119cad78ca2SJerin Jacob } 120cad78ca2SJerin Jacob 121cad78ca2SJerin Jacob /** 122cad78ca2SJerin Jacob * Close a PKO DQ 123cad78ca2SJerin Jacob * Flush all packets pending. 124cad78ca2SJerin Jacob */ 125cad78ca2SJerin Jacob static inline 126cad78ca2SJerin Jacob int octeontx_pko_dq_close(uint16_t txq) 127cad78ca2SJerin Jacob { 128cad78ca2SJerin Jacob unsigned int reg_off; 129cad78ca2SJerin Jacob uint8_t *vf_bar0; 130cad78ca2SJerin Jacob uint64_t rtn; 131cad78ca2SJerin Jacob int res; 132cad78ca2SJerin Jacob 133cad78ca2SJerin Jacob vf_bar0 = octeontx_pko_dq_vf_bar0(txq); 134cad78ca2SJerin Jacob res = octeontx_pko_dq_gdq(txq); 135cad78ca2SJerin Jacob 136cad78ca2SJerin Jacob if (unlikely(res < 0 || vf_bar0 == NULL)) 137cad78ca2SJerin Jacob return -EINVAL; 138cad78ca2SJerin Jacob 139cad78ca2SJerin Jacob reg_off = PKO_VF_DQ_OP_CLOSE(res); 140cad78ca2SJerin Jacob 141cad78ca2SJerin Jacob rtn = octeontx_reg_ldadd_u64(vf_bar0 + reg_off, 0); 142cad78ca2SJerin Jacob 143cad78ca2SJerin Jacob /* PKO_DQOP_E::CLOSE */ 144cad78ca2SJerin Jacob if (((rtn >> PKO_DQ_OP_BIT) & 0x3) != 0x2) 145cad78ca2SJerin Jacob return -EIO; 146cad78ca2SJerin Jacob 147cad78ca2SJerin Jacob switch (rtn >> PKO_DQ_STATUS_BIT) { 148cad78ca2SJerin Jacob case 0xD: /* DQNOTCREATED */ 149cad78ca2SJerin Jacob case 0x0: /* PASS */ 150cad78ca2SJerin Jacob break; 151cad78ca2SJerin Jacob default: 152cad78ca2SJerin Jacob return -EIO; 153cad78ca2SJerin Jacob } 154cad78ca2SJerin Jacob 155cad78ca2SJerin Jacob res = rtn & ((1ull << PKO_DQ_OP_BIT) - 1); /* DEPTH */ 156cad78ca2SJerin Jacob return res; 157cad78ca2SJerin Jacob } 158cad78ca2SJerin Jacob 159cad78ca2SJerin Jacob /* Flush all packets pending on a DQ */ 160cad78ca2SJerin Jacob static inline 161cad78ca2SJerin Jacob int octeontx_pko_dq_drain(uint16_t txq) 162cad78ca2SJerin Jacob { 163cad78ca2SJerin Jacob unsigned int gdq; 164cad78ca2SJerin Jacob uint8_t *vf_bar0; 165cad78ca2SJerin Jacob uint64_t reg; 166cad78ca2SJerin Jacob int res, timo = PKO_DQ_DRAIN_TO; 167cad78ca2SJerin Jacob 168cad78ca2SJerin Jacob vf_bar0 = octeontx_pko_dq_vf_bar0(txq); 169cad78ca2SJerin Jacob res = octeontx_pko_dq_gdq(txq); 170cad78ca2SJerin Jacob gdq = res; 171cad78ca2SJerin Jacob 172cad78ca2SJerin Jacob /* DRAIN=1, DRAIN_NULL_LINK=0, SW_XOFF=1 */ 173cad78ca2SJerin Jacob octeontx_write64(0x3, vf_bar0 + PKO_VF_DQ_SW_XOFF(gdq)); 174cad78ca2SJerin Jacob /* Wait until buffers leave DQs */ 175cad78ca2SJerin Jacob reg = octeontx_read64(vf_bar0 + PKO_VF_DQ_WM_CNT(gdq)); 176cad78ca2SJerin Jacob while (reg && timo > 0) { 177cad78ca2SJerin Jacob rte_delay_us(100); 178cad78ca2SJerin Jacob timo--; 179cad78ca2SJerin Jacob reg = octeontx_read64(vf_bar0 + PKO_VF_DQ_WM_CNT(gdq)); 180cad78ca2SJerin Jacob } 181cad78ca2SJerin Jacob /* DRAIN=0, DRAIN_NULL_LINK=0, SW_XOFF=0 */ 182cad78ca2SJerin Jacob octeontx_write64(0, vf_bar0 + PKO_VF_DQ_SW_XOFF(gdq)); 183cad78ca2SJerin Jacob 184cad78ca2SJerin Jacob return reg; 185cad78ca2SJerin Jacob } 186cad78ca2SJerin Jacob 187cad78ca2SJerin Jacob static inline int 188cad78ca2SJerin Jacob octeontx_pko_dq_range_lookup(struct octeontx_pko_vf_ctl_s *ctl, uint64_t chanid, 189cad78ca2SJerin Jacob unsigned int dq_num, unsigned int dq_from) 190cad78ca2SJerin Jacob { 191cad78ca2SJerin Jacob unsigned int dq, dq_cnt; 192cad78ca2SJerin Jacob unsigned int dq_base; 193cad78ca2SJerin Jacob 194cad78ca2SJerin Jacob dq_cnt = 0; 195cad78ca2SJerin Jacob dq = dq_from; 196cad78ca2SJerin Jacob while (dq < RTE_DIM(ctl->dq_map)) { 197cad78ca2SJerin Jacob dq_base = dq; 198cad78ca2SJerin Jacob dq_cnt = 0; 199cad78ca2SJerin Jacob while (ctl->dq_map[dq].chanid == ~chanid && 200cad78ca2SJerin Jacob dq < RTE_DIM(ctl->dq_map)) { 201cad78ca2SJerin Jacob dq_cnt++; 202cad78ca2SJerin Jacob if (dq_cnt == dq_num) 203cad78ca2SJerin Jacob return dq_base; 204cad78ca2SJerin Jacob dq++; 205cad78ca2SJerin Jacob } 206cad78ca2SJerin Jacob dq++; 207cad78ca2SJerin Jacob } 208cad78ca2SJerin Jacob return -1; 209cad78ca2SJerin Jacob } 210cad78ca2SJerin Jacob 211cad78ca2SJerin Jacob static inline void 212cad78ca2SJerin Jacob octeontx_pko_dq_range_assign(struct octeontx_pko_vf_ctl_s *ctl, uint64_t chanid, 213cad78ca2SJerin Jacob unsigned int dq_base, unsigned int dq_num) 214cad78ca2SJerin Jacob { 215cad78ca2SJerin Jacob unsigned int dq, dq_cnt; 216cad78ca2SJerin Jacob 217cad78ca2SJerin Jacob dq_cnt = 0; 218cad78ca2SJerin Jacob while (dq_cnt < dq_num) { 219cad78ca2SJerin Jacob dq = dq_base + dq_cnt; 220cad78ca2SJerin Jacob 221cad78ca2SJerin Jacob octeontx_log_dbg("DQ# %u assigned to CHAN# %" PRIx64 "", dq, 222cad78ca2SJerin Jacob chanid); 223cad78ca2SJerin Jacob 224cad78ca2SJerin Jacob ctl->dq_map[dq].chanid = ~chanid; 225cad78ca2SJerin Jacob dq_cnt++; 226cad78ca2SJerin Jacob } 227cad78ca2SJerin Jacob } 228cad78ca2SJerin Jacob 229cad78ca2SJerin Jacob static inline int 230cad78ca2SJerin Jacob octeontx_pko_dq_claim(struct octeontx_pko_vf_ctl_s *ctl, unsigned int dq_base, 231cad78ca2SJerin Jacob unsigned int dq_num, uint64_t chanid) 232cad78ca2SJerin Jacob { 233cad78ca2SJerin Jacob const uint64_t null_chanid = ~0ull; 234cad78ca2SJerin Jacob int dq; 235cad78ca2SJerin Jacob 236cad78ca2SJerin Jacob rte_spinlock_lock(&ctl->lock); 237cad78ca2SJerin Jacob 238cad78ca2SJerin Jacob dq = octeontx_pko_dq_range_lookup(ctl, null_chanid, dq_num, dq_base); 239cad78ca2SJerin Jacob if (dq < 0 || (unsigned int)dq != dq_base) { 240cad78ca2SJerin Jacob rte_spinlock_unlock(&ctl->lock); 241cad78ca2SJerin Jacob return -1; 242cad78ca2SJerin Jacob } 243cad78ca2SJerin Jacob octeontx_pko_dq_range_assign(ctl, chanid, dq_base, dq_num); 244cad78ca2SJerin Jacob 245cad78ca2SJerin Jacob rte_spinlock_unlock(&ctl->lock); 246cad78ca2SJerin Jacob 247cad78ca2SJerin Jacob return 0; 248cad78ca2SJerin Jacob } 249cad78ca2SJerin Jacob 250cad78ca2SJerin Jacob static inline int 251cad78ca2SJerin Jacob octeontx_pko_dq_free(struct octeontx_pko_vf_ctl_s *ctl, uint64_t chanid) 252cad78ca2SJerin Jacob { 253cad78ca2SJerin Jacob const uint64_t null_chanid = ~0ull; 254cad78ca2SJerin Jacob unsigned int dq = 0, dq_cnt = 0; 255cad78ca2SJerin Jacob 256cad78ca2SJerin Jacob rte_spinlock_lock(&ctl->lock); 257cad78ca2SJerin Jacob while (dq < RTE_DIM(ctl->dq_map)) { 258cad78ca2SJerin Jacob if (ctl->dq_map[dq].chanid == ~chanid) { 259cad78ca2SJerin Jacob ctl->dq_map[dq].chanid = ~null_chanid; 260cad78ca2SJerin Jacob dq_cnt++; 261cad78ca2SJerin Jacob } 262cad78ca2SJerin Jacob dq++; 263cad78ca2SJerin Jacob } 264cad78ca2SJerin Jacob rte_spinlock_unlock(&ctl->lock); 265cad78ca2SJerin Jacob 266cad78ca2SJerin Jacob return dq_cnt > 0 ? 0 : -EINVAL; 267cad78ca2SJerin Jacob } 268cad78ca2SJerin Jacob 269cad78ca2SJerin Jacob int 270cad78ca2SJerin Jacob octeontx_pko_channel_open(int dq_base, int dq_num, int chanid) 271cad78ca2SJerin Jacob { 272cad78ca2SJerin Jacob struct octeontx_pko_vf_ctl_s *ctl = &pko_vf_ctl; 273cad78ca2SJerin Jacob int res; 274cad78ca2SJerin Jacob 275cad78ca2SJerin Jacob res = octeontx_pko_dq_claim(ctl, dq_base, dq_num, chanid); 276cad78ca2SJerin Jacob if (res < 0) 277cad78ca2SJerin Jacob return -1; 278cad78ca2SJerin Jacob 279cad78ca2SJerin Jacob return 0; 280cad78ca2SJerin Jacob } 281cad78ca2SJerin Jacob 282cad78ca2SJerin Jacob int 283cad78ca2SJerin Jacob octeontx_pko_channel_close(int chanid) 284cad78ca2SJerin Jacob { 285cad78ca2SJerin Jacob struct octeontx_pko_vf_ctl_s *ctl = &pko_vf_ctl; 286cad78ca2SJerin Jacob int res; 287cad78ca2SJerin Jacob 288cad78ca2SJerin Jacob res = octeontx_pko_dq_free(ctl, chanid); 289cad78ca2SJerin Jacob if (res < 0) 290cad78ca2SJerin Jacob return -1; 291cad78ca2SJerin Jacob 292cad78ca2SJerin Jacob return 0; 293cad78ca2SJerin Jacob } 294cad78ca2SJerin Jacob 295cad78ca2SJerin Jacob static inline int 296cad78ca2SJerin Jacob octeontx_pko_chan_start(struct octeontx_pko_vf_ctl_s *ctl, uint64_t chanid) 297cad78ca2SJerin Jacob { 298cad78ca2SJerin Jacob unsigned int dq_vf; 299cad78ca2SJerin Jacob unsigned int dq, dq_cnt; 300cad78ca2SJerin Jacob 301cad78ca2SJerin Jacob dq_cnt = 0; 302cad78ca2SJerin Jacob dq = 0; 303cad78ca2SJerin Jacob while (dq < RTE_DIM(ctl->dq_map)) { 304cad78ca2SJerin Jacob dq_vf = dq / PKO_VF_NUM_DQ; 305cad78ca2SJerin Jacob 306cad78ca2SJerin Jacob if (!ctl->pko[dq_vf].bar0) { 307cad78ca2SJerin Jacob dq += PKO_VF_NUM_DQ; 308cad78ca2SJerin Jacob continue; 309cad78ca2SJerin Jacob } 310cad78ca2SJerin Jacob 311cad78ca2SJerin Jacob if (ctl->dq_map[dq].chanid != ~chanid) { 312cad78ca2SJerin Jacob dq++; 313cad78ca2SJerin Jacob continue; 314cad78ca2SJerin Jacob } 315cad78ca2SJerin Jacob 316cad78ca2SJerin Jacob if (octeontx_pko_dq_open(dq) < 0) 317cad78ca2SJerin Jacob break; 318cad78ca2SJerin Jacob 319cad78ca2SJerin Jacob dq_cnt++; 320cad78ca2SJerin Jacob dq++; 321cad78ca2SJerin Jacob } 322cad78ca2SJerin Jacob 323cad78ca2SJerin Jacob return dq_cnt; 324cad78ca2SJerin Jacob } 325cad78ca2SJerin Jacob 326cad78ca2SJerin Jacob int 327cad78ca2SJerin Jacob octeontx_pko_channel_start(int chanid) 328cad78ca2SJerin Jacob { 329cad78ca2SJerin Jacob struct octeontx_pko_vf_ctl_s *ctl = &pko_vf_ctl; 330cad78ca2SJerin Jacob int dq_cnt; 331cad78ca2SJerin Jacob 332cad78ca2SJerin Jacob dq_cnt = octeontx_pko_chan_start(ctl, chanid); 333cad78ca2SJerin Jacob if (dq_cnt < 0) 334cad78ca2SJerin Jacob return -1; 335cad78ca2SJerin Jacob 336cad78ca2SJerin Jacob return dq_cnt; 337cad78ca2SJerin Jacob } 338cad78ca2SJerin Jacob 339cad78ca2SJerin Jacob static inline int 340cad78ca2SJerin Jacob octeontx_pko_chan_stop(struct octeontx_pko_vf_ctl_s *ctl, uint64_t chanid) 341cad78ca2SJerin Jacob { 342cad78ca2SJerin Jacob unsigned int dq, dq_cnt, dq_vf; 343cad78ca2SJerin Jacob int res; 344cad78ca2SJerin Jacob 345cad78ca2SJerin Jacob dq_cnt = 0; 346cad78ca2SJerin Jacob dq = 0; 347cad78ca2SJerin Jacob while (dq < RTE_DIM(ctl->dq_map)) { 348cad78ca2SJerin Jacob dq_vf = dq / PKO_VF_NUM_DQ; 349cad78ca2SJerin Jacob 350cad78ca2SJerin Jacob if (!ctl->pko[dq_vf].bar0) { 351cad78ca2SJerin Jacob dq += PKO_VF_NUM_DQ; 352cad78ca2SJerin Jacob continue; 353cad78ca2SJerin Jacob } 354cad78ca2SJerin Jacob 355cad78ca2SJerin Jacob if (ctl->dq_map[dq].chanid != ~chanid) { 356cad78ca2SJerin Jacob dq++; 357cad78ca2SJerin Jacob continue; 358cad78ca2SJerin Jacob } 359cad78ca2SJerin Jacob 360cad78ca2SJerin Jacob res = octeontx_pko_dq_drain(dq); 361cad78ca2SJerin Jacob if (res > 0) 362cad78ca2SJerin Jacob octeontx_log_err("draining DQ%d, buffers left: %x", 363cad78ca2SJerin Jacob dq, res); 364cad78ca2SJerin Jacob 365cad78ca2SJerin Jacob res = octeontx_pko_dq_close(dq); 366cad78ca2SJerin Jacob if (res < 0) 367*f665790aSDavid Marchand octeontx_log_err("closing DQ%d failed", dq); 368cad78ca2SJerin Jacob 369cad78ca2SJerin Jacob dq_cnt++; 370cad78ca2SJerin Jacob dq++; 371cad78ca2SJerin Jacob } 372cad78ca2SJerin Jacob return dq_cnt; 373cad78ca2SJerin Jacob } 374cad78ca2SJerin Jacob 375cad78ca2SJerin Jacob int 376cad78ca2SJerin Jacob octeontx_pko_channel_stop(int chanid) 377cad78ca2SJerin Jacob { 378cad78ca2SJerin Jacob struct octeontx_pko_vf_ctl_s *ctl = &pko_vf_ctl; 379cad78ca2SJerin Jacob 380cad78ca2SJerin Jacob octeontx_pko_chan_stop(ctl, chanid); 381cad78ca2SJerin Jacob return 0; 382cad78ca2SJerin Jacob } 383cad78ca2SJerin Jacob 3843813a10aSJerin Jacob static inline int 3853813a10aSJerin Jacob octeontx_pko_channel_query(struct octeontx_pko_vf_ctl_s *ctl, uint64_t chanid, 3863813a10aSJerin Jacob void *out, size_t out_elem_size, 3873813a10aSJerin Jacob size_t dq_num, octeontx_pko_dq_getter_t getter) 3883813a10aSJerin Jacob { 3893813a10aSJerin Jacob octeontx_dq_t curr; 3903813a10aSJerin Jacob unsigned int dq_vf; 3913813a10aSJerin Jacob unsigned int dq; 3923813a10aSJerin Jacob 3933813a10aSJerin Jacob RTE_SET_USED(out_elem_size); 3943813a10aSJerin Jacob memset(&curr, 0, sizeof(octeontx_dq_t)); 3953813a10aSJerin Jacob 3963813a10aSJerin Jacob dq_vf = dq_num / PKO_VF_NUM_DQ; 3973813a10aSJerin Jacob dq = dq_num % PKO_VF_NUM_DQ; 3983813a10aSJerin Jacob 3993813a10aSJerin Jacob if (!ctl->pko[dq_vf].bar0) 4003813a10aSJerin Jacob return -EINVAL; 4013813a10aSJerin Jacob 4023813a10aSJerin Jacob if (ctl->dq_map[dq_num].chanid != ~chanid) 4033813a10aSJerin Jacob return -EINVAL; 4043813a10aSJerin Jacob 4053813a10aSJerin Jacob uint8_t *iter = (uint8_t *)out; 4063813a10aSJerin Jacob curr.lmtline_va = ctl->pko[dq_vf].bar2; 4073813a10aSJerin Jacob curr.ioreg_va = (void *)((uintptr_t)ctl->pko[dq_vf].bar0 4083813a10aSJerin Jacob + PKO_VF_DQ_OP_SEND((dq), 0)); 409a6d6f0afSPavan Nikhilesh curr.fc_status_va = ctl->fc_ctl + dq_num; 4103813a10aSJerin Jacob 4113813a10aSJerin Jacob octeontx_log_dbg("lmtline=%p ioreg_va=%p fc_status_va=%p", 4123813a10aSJerin Jacob curr.lmtline_va, curr.ioreg_va, 4133813a10aSJerin Jacob curr.fc_status_va); 4143813a10aSJerin Jacob 4153813a10aSJerin Jacob getter(&curr, (void *)iter); 4163813a10aSJerin Jacob return 0; 4173813a10aSJerin Jacob } 4183813a10aSJerin Jacob 4193813a10aSJerin Jacob int 4203813a10aSJerin Jacob octeontx_pko_channel_query_dqs(int chanid, void *out, size_t out_elem_size, 4213813a10aSJerin Jacob size_t dq_num, octeontx_pko_dq_getter_t getter) 4223813a10aSJerin Jacob { 4233813a10aSJerin Jacob struct octeontx_pko_vf_ctl_s *ctl = &pko_vf_ctl; 4243813a10aSJerin Jacob int dq_cnt; 4253813a10aSJerin Jacob 4263813a10aSJerin Jacob dq_cnt = octeontx_pko_channel_query(ctl, chanid, out, out_elem_size, 4273813a10aSJerin Jacob dq_num, getter); 4283813a10aSJerin Jacob if (dq_cnt < 0) 4293813a10aSJerin Jacob return -1; 4303813a10aSJerin Jacob 4313813a10aSJerin Jacob return dq_cnt; 4323813a10aSJerin Jacob } 4333813a10aSJerin Jacob 4343813a10aSJerin Jacob int 4353813a10aSJerin Jacob octeontx_pko_vf_count(void) 4363813a10aSJerin Jacob { 437a6d6f0afSPavan Nikhilesh uint16_t global_domain = octeontx_get_global_domain(); 4383813a10aSJerin Jacob int vf_cnt; 4393813a10aSJerin Jacob 440a6d6f0afSPavan Nikhilesh pko_vf_ctl.global_domain = global_domain; 4413813a10aSJerin Jacob vf_cnt = 0; 4423813a10aSJerin Jacob while (pko_vf_ctl.pko[vf_cnt].bar0) 4433813a10aSJerin Jacob vf_cnt++; 4443813a10aSJerin Jacob 4453813a10aSJerin Jacob return vf_cnt; 4463813a10aSJerin Jacob } 4473813a10aSJerin Jacob 448a6d6f0afSPavan Nikhilesh size_t 449a6d6f0afSPavan Nikhilesh octeontx_pko_get_vfid(void) 450a6d6f0afSPavan Nikhilesh { 451a6d6f0afSPavan Nikhilesh size_t vf_cnt = octeontx_pko_vf_count(); 452a6d6f0afSPavan Nikhilesh size_t vf_idx; 453a6d6f0afSPavan Nikhilesh 454a6d6f0afSPavan Nikhilesh 455a6d6f0afSPavan Nikhilesh for (vf_idx = 0; vf_idx < vf_cnt; vf_idx++) { 456a6d6f0afSPavan Nikhilesh if (!(pko_vf_ctl.pko[vf_idx].status & PKO_VALID)) 457a6d6f0afSPavan Nikhilesh continue; 458a6d6f0afSPavan Nikhilesh if (pko_vf_ctl.pko[vf_idx].status & PKO_INUSE) 459a6d6f0afSPavan Nikhilesh continue; 460a6d6f0afSPavan Nikhilesh 461a6d6f0afSPavan Nikhilesh pko_vf_ctl.pko[vf_idx].status |= PKO_INUSE; 462a6d6f0afSPavan Nikhilesh return pko_vf_ctl.pko[vf_idx].vfid; 463a6d6f0afSPavan Nikhilesh } 464a6d6f0afSPavan Nikhilesh 465a6d6f0afSPavan Nikhilesh return SIZE_MAX; 466a6d6f0afSPavan Nikhilesh } 467a6d6f0afSPavan Nikhilesh 4683813a10aSJerin Jacob int 4693151e6a6SHarman Kalra octeontx_pko_send_mtu(int port, int mtu) 4703151e6a6SHarman Kalra { 4713151e6a6SHarman Kalra struct octeontx_mbox_hdr hdr; 4723151e6a6SHarman Kalra int res; 4733151e6a6SHarman Kalra mbox_pko_mtu_cfg_t cfg; 4743151e6a6SHarman Kalra 4753151e6a6SHarman Kalra cfg.mtu = mtu; 4763151e6a6SHarman Kalra 4773151e6a6SHarman Kalra hdr.coproc = OCTEONTX_PKO_COPROC; 4783151e6a6SHarman Kalra hdr.msg = MBOX_PKO_MTU_CONFIG; 4793151e6a6SHarman Kalra hdr.vfid = port; 4803151e6a6SHarman Kalra 4813151e6a6SHarman Kalra res = octeontx_mbox_send(&hdr, &cfg, sizeof(mbox_pko_mtu_cfg_t), 4823151e6a6SHarman Kalra NULL, 0); 4833151e6a6SHarman Kalra if (res < 0) 4843151e6a6SHarman Kalra return -EACCES; 4853151e6a6SHarman Kalra 4863151e6a6SHarman Kalra return res; 4873151e6a6SHarman Kalra } 4883151e6a6SHarman Kalra 4893151e6a6SHarman Kalra int 4903813a10aSJerin Jacob octeontx_pko_init_fc(const size_t pko_vf_count) 4913813a10aSJerin Jacob { 4923813a10aSJerin Jacob int dq_ix; 4933813a10aSJerin Jacob uint64_t reg; 4943813a10aSJerin Jacob uint8_t *vf_bar0; 4953813a10aSJerin Jacob size_t vf_idx; 4963813a10aSJerin Jacob size_t fc_mem_size; 4973813a10aSJerin Jacob 4983813a10aSJerin Jacob fc_mem_size = sizeof(struct octeontx_pko_fc_ctl_s) * 4993813a10aSJerin Jacob pko_vf_count * PKO_VF_NUM_DQ; 5003813a10aSJerin Jacob 5013813a10aSJerin Jacob pko_vf_ctl.fc_iomem.va = rte_malloc(NULL, fc_mem_size, 128); 5023813a10aSJerin Jacob if (unlikely(!pko_vf_ctl.fc_iomem.va)) { 5033813a10aSJerin Jacob octeontx_log_err("fc_iomem: not enough memory"); 5043813a10aSJerin Jacob return -ENOMEM; 5053813a10aSJerin Jacob } 5063813a10aSJerin Jacob 50787cf4c6cSThomas Monjalon pko_vf_ctl.fc_iomem.iova = rte_malloc_virt2iova((void *) 5083813a10aSJerin Jacob pko_vf_ctl.fc_iomem.va); 5093813a10aSJerin Jacob pko_vf_ctl.fc_iomem.size = fc_mem_size; 5103813a10aSJerin Jacob 5113813a10aSJerin Jacob pko_vf_ctl.fc_ctl = 5123813a10aSJerin Jacob (struct octeontx_pko_fc_ctl_s *)pko_vf_ctl.fc_iomem.va; 5133813a10aSJerin Jacob 5143813a10aSJerin Jacob /* Configure Flow-Control feature for all DQs of open VFs */ 5153813a10aSJerin Jacob for (vf_idx = 0; vf_idx < pko_vf_count; vf_idx++) { 516a6d6f0afSPavan Nikhilesh if (pko_vf_ctl.pko[vf_idx].domain != pko_vf_ctl.global_domain) 517a6d6f0afSPavan Nikhilesh continue; 5183813a10aSJerin Jacob 519a6d6f0afSPavan Nikhilesh dq_ix = pko_vf_ctl.pko[vf_idx].vfid * PKO_VF_NUM_DQ; 5203813a10aSJerin Jacob vf_bar0 = pko_vf_ctl.pko[vf_idx].bar0; 5213813a10aSJerin Jacob 5223813a10aSJerin Jacob reg = (pko_vf_ctl.fc_iomem.iova + 5233813a10aSJerin Jacob (sizeof(struct octeontx_pko_fc_ctl_s) * dq_ix)) & ~0x7F; 5243813a10aSJerin Jacob reg |= /* BASE */ 5253813a10aSJerin Jacob (0x2 << 3) | /* HYST_BITS */ 5263813a10aSJerin Jacob (((PKO_DQ_FC_STRIDE == PKO_DQ_FC_STRIDE_16) ? 1 : 0) << 2) | 5273813a10aSJerin Jacob (0x1 << 0); /* ENABLE */ 5283813a10aSJerin Jacob 5293813a10aSJerin Jacob octeontx_write64(reg, vf_bar0 + PKO_VF_DQ_FC_CONFIG); 530a6d6f0afSPavan Nikhilesh pko_vf_ctl.pko[vf_idx].status = PKO_VALID; 5313813a10aSJerin Jacob 5323813a10aSJerin Jacob octeontx_log_dbg("PKO: bar0 %p VF_idx %d DQ_FC_CFG=%" PRIx64 "", 5333813a10aSJerin Jacob vf_bar0, (int)vf_idx, reg); 5343813a10aSJerin Jacob } 5353813a10aSJerin Jacob return 0; 5363813a10aSJerin Jacob } 5373813a10aSJerin Jacob 5383813a10aSJerin Jacob void 5393813a10aSJerin Jacob octeontx_pko_fc_free(void) 5403813a10aSJerin Jacob { 5413813a10aSJerin Jacob rte_free(pko_vf_ctl.fc_iomem.va); 5423813a10aSJerin Jacob } 5433813a10aSJerin Jacob 544445371e8SJerin Jacob static void 545445371e8SJerin Jacob octeontx_pkovf_setup(void) 546445371e8SJerin Jacob { 547445371e8SJerin Jacob static bool init_once; 548445371e8SJerin Jacob 549445371e8SJerin Jacob if (!init_once) { 550445371e8SJerin Jacob unsigned int i; 551445371e8SJerin Jacob 552445371e8SJerin Jacob rte_spinlock_init(&pko_vf_ctl.lock); 553445371e8SJerin Jacob 554445371e8SJerin Jacob pko_vf_ctl.fc_iomem = PKO_IOMEM_NULL; 555445371e8SJerin Jacob pko_vf_ctl.fc_ctl = NULL; 556445371e8SJerin Jacob 557445371e8SJerin Jacob for (i = 0; i < PKO_VF_MAX; i++) { 558445371e8SJerin Jacob pko_vf_ctl.pko[i].bar0 = NULL; 559445371e8SJerin Jacob pko_vf_ctl.pko[i].bar2 = NULL; 560445371e8SJerin Jacob pko_vf_ctl.pko[i].domain = ~(uint16_t)0; 561445371e8SJerin Jacob pko_vf_ctl.pko[i].vfid = ~(uint16_t)0; 562445371e8SJerin Jacob } 563445371e8SJerin Jacob 564445371e8SJerin Jacob for (i = 0; i < (PKO_VF_MAX * PKO_VF_NUM_DQ); i++) 565445371e8SJerin Jacob pko_vf_ctl.dq_map[i].chanid = 0; 566445371e8SJerin Jacob 567445371e8SJerin Jacob init_once = true; 568445371e8SJerin Jacob } 569445371e8SJerin Jacob } 570445371e8SJerin Jacob 571445371e8SJerin Jacob /* PKOVF pcie device*/ 572445371e8SJerin Jacob static int 573445371e8SJerin Jacob pkovf_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev) 574445371e8SJerin Jacob { 575445371e8SJerin Jacob uint64_t val; 576445371e8SJerin Jacob uint16_t vfid; 577445371e8SJerin Jacob uint16_t domain; 578445371e8SJerin Jacob uint8_t *bar0; 579445371e8SJerin Jacob uint8_t *bar2; 580a6d6f0afSPavan Nikhilesh static uint8_t vf_cnt; 581445371e8SJerin Jacob struct octeontx_pkovf *res; 582445371e8SJerin Jacob 583445371e8SJerin Jacob RTE_SET_USED(pci_drv); 584445371e8SJerin Jacob 585445371e8SJerin Jacob /* For secondary processes, the primary has done all the work */ 586445371e8SJerin Jacob if (rte_eal_process_type() != RTE_PROC_PRIMARY) 587445371e8SJerin Jacob return 0; 588445371e8SJerin Jacob 589445371e8SJerin Jacob if (pci_dev->mem_resource[0].addr == NULL || 590445371e8SJerin Jacob pci_dev->mem_resource[2].addr == NULL) { 591445371e8SJerin Jacob octeontx_log_err("Empty bars %p %p", 592445371e8SJerin Jacob pci_dev->mem_resource[0].addr, 593445371e8SJerin Jacob pci_dev->mem_resource[2].addr); 594445371e8SJerin Jacob return -ENODEV; 595445371e8SJerin Jacob } 596445371e8SJerin Jacob bar0 = pci_dev->mem_resource[0].addr; 597445371e8SJerin Jacob bar2 = pci_dev->mem_resource[2].addr; 598445371e8SJerin Jacob 599445371e8SJerin Jacob octeontx_pkovf_setup(); 600445371e8SJerin Jacob 601445371e8SJerin Jacob /* get vfid and domain */ 602445371e8SJerin Jacob val = octeontx_read64(bar0 + PKO_VF_DQ_FC_CONFIG); 603445371e8SJerin Jacob domain = (val >> 7) & 0xffff; 604445371e8SJerin Jacob vfid = (val >> 23) & 0xffff; 605445371e8SJerin Jacob 606445371e8SJerin Jacob if (unlikely(vfid >= PKO_VF_MAX)) { 607445371e8SJerin Jacob octeontx_log_err("pko: Invalid vfid %d", vfid); 608445371e8SJerin Jacob return -EINVAL; 609445371e8SJerin Jacob } 610445371e8SJerin Jacob 611a6d6f0afSPavan Nikhilesh res = &pko_vf_ctl.pko[vf_cnt++]; 612445371e8SJerin Jacob res->vfid = vfid; 613445371e8SJerin Jacob res->domain = domain; 614445371e8SJerin Jacob res->bar0 = bar0; 615445371e8SJerin Jacob res->bar2 = bar2; 616445371e8SJerin Jacob 617445371e8SJerin Jacob octeontx_log_dbg("Domain=%d group=%d", res->domain, res->vfid); 618445371e8SJerin Jacob return 0; 619445371e8SJerin Jacob } 620445371e8SJerin Jacob 621445371e8SJerin Jacob #define PCI_VENDOR_ID_CAVIUM 0x177D 622445371e8SJerin Jacob #define PCI_DEVICE_ID_OCTEONTX_PKO_VF 0xA049 623445371e8SJerin Jacob 624445371e8SJerin Jacob static const struct rte_pci_id pci_pkovf_map[] = { 625445371e8SJerin Jacob { 626445371e8SJerin Jacob RTE_PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, 627445371e8SJerin Jacob PCI_DEVICE_ID_OCTEONTX_PKO_VF) 628445371e8SJerin Jacob }, 629445371e8SJerin Jacob { 630445371e8SJerin Jacob .vendor_id = 0, 631445371e8SJerin Jacob }, 632445371e8SJerin Jacob }; 633445371e8SJerin Jacob 634445371e8SJerin Jacob static struct rte_pci_driver pci_pkovf = { 635445371e8SJerin Jacob .id_table = pci_pkovf_map, 636445371e8SJerin Jacob .drv_flags = RTE_PCI_DRV_NEED_MAPPING, 637445371e8SJerin Jacob .probe = pkovf_probe, 638445371e8SJerin Jacob }; 639445371e8SJerin Jacob 640445371e8SJerin Jacob RTE_PMD_REGISTER_PCI(octeontx_pkovf, pci_pkovf); 641