// SPDX-License-Identifier: GPL-2.0 /* Marvell OcteonTx2 RVU Physcial Function ethernet driver * * Copyright (C) 2020 Marvell. */ #include "cn10k.h" #include "otx2_reg.h" #include "otx2_struct.h" static struct dev_hw_ops otx2_hw_ops = { .sq_aq_init = otx2_sq_aq_init, .sqe_flush = otx2_sqe_flush, .aura_freeptr = otx2_aura_freeptr, .refill_pool_ptrs = otx2_refill_pool_ptrs, }; static struct dev_hw_ops cn10k_hw_ops = { .sq_aq_init = cn10k_sq_aq_init, .sqe_flush = cn10k_sqe_flush, .aura_freeptr = cn10k_aura_freeptr, .refill_pool_ptrs = cn10k_refill_pool_ptrs, }; int cn10k_pf_lmtst_init(struct otx2_nic *pf) { int size, num_lines; u64 base; if (!test_bit(CN10K_LMTST, &pf->hw.cap_flag)) { pf->hw_ops = &otx2_hw_ops; return 0; } pf->hw_ops = &cn10k_hw_ops; base = pci_resource_start(pf->pdev, PCI_MBOX_BAR_NUM) + (MBOX_SIZE * (pf->total_vfs + 1)); size = pci_resource_len(pf->pdev, PCI_MBOX_BAR_NUM) - (MBOX_SIZE * (pf->total_vfs + 1)); pf->hw.lmt_base = ioremap(base, size); if (!pf->hw.lmt_base) { dev_err(pf->dev, "Unable to map PF LMTST region\n"); return -ENOMEM; } /* FIXME: Get the num of LMTST lines from LMT table */ pf->tot_lmt_lines = size / LMT_LINE_SIZE; num_lines = (pf->tot_lmt_lines - NIX_LMTID_BASE) / pf->hw.tx_queues; /* Number of LMT lines per SQ queues */ pf->nix_lmt_lines = num_lines > 32 ? 32 : num_lines; pf->nix_lmt_size = pf->nix_lmt_lines * LMT_LINE_SIZE; return 0; } int cn10k_vf_lmtst_init(struct otx2_nic *vf) { int size, num_lines; if (!test_bit(CN10K_LMTST, &vf->hw.cap_flag)) { vf->hw_ops = &otx2_hw_ops; return 0; } vf->hw_ops = &cn10k_hw_ops; size = pci_resource_len(vf->pdev, PCI_MBOX_BAR_NUM); vf->hw.lmt_base = ioremap_wc(pci_resource_start(vf->pdev, PCI_MBOX_BAR_NUM), size); if (!vf->hw.lmt_base) { dev_err(vf->dev, "Unable to map VF LMTST region\n"); return -ENOMEM; } vf->tot_lmt_lines = size / LMT_LINE_SIZE; /* LMTST lines per SQ */ num_lines = (vf->tot_lmt_lines - NIX_LMTID_BASE) / vf->hw.tx_queues; vf->nix_lmt_lines = num_lines > 32 ? 32 : num_lines; vf->nix_lmt_size = vf->nix_lmt_lines * LMT_LINE_SIZE; return 0; } EXPORT_SYMBOL(cn10k_vf_lmtst_init); int cn10k_sq_aq_init(void *dev, u16 qidx, u16 sqb_aura) { struct nix_cn10k_aq_enq_req *aq; struct otx2_nic *pfvf = dev; struct otx2_snd_queue *sq; sq = &pfvf->qset.sq[qidx]; sq->lmt_addr = (__force u64 *)((u64)pfvf->hw.nix_lmt_base + (qidx * pfvf->nix_lmt_size)); /* Get memory to put this msg */ aq = otx2_mbox_alloc_msg_nix_cn10k_aq_enq(&pfvf->mbox); if (!aq) return -ENOMEM; aq->sq.cq = pfvf->hw.rx_queues + qidx; aq->sq.max_sqe_size = NIX_MAXSQESZ_W16; /* 128 byte */ aq->sq.cq_ena = 1; aq->sq.ena = 1; /* Only one SMQ is allocated, map all SQ's to that SMQ */ aq->sq.smq = pfvf->hw.txschq_list[NIX_TXSCH_LVL_SMQ][0]; /* FIXME: set based on NIX_AF_DWRR_RPM_MTU*/ aq->sq.smq_rr_weight = pfvf->netdev->mtu; aq->sq.default_chan = pfvf->hw.tx_chan_base; aq->sq.sqe_stype = NIX_STYPE_STF; /* Cache SQB */ aq->sq.sqb_aura = sqb_aura; aq->sq.sq_int_ena = NIX_SQINT_BITS; aq->sq.qint_idx = 0; /* Due pipelining impact minimum 2000 unused SQ CQE's * need to maintain to avoid CQ overflow. */ aq->sq.cq_limit = ((SEND_CQ_SKID * 256) / (pfvf->qset.sqe_cnt)); /* Fill AQ info */ aq->qidx = qidx; aq->ctype = NIX_AQ_CTYPE_SQ; aq->op = NIX_AQ_INSTOP_INIT; return otx2_sync_mbox_msg(&pfvf->mbox); } #define NPA_MAX_BURST 16 void cn10k_refill_pool_ptrs(void *dev, struct otx2_cq_queue *cq) { struct otx2_nic *pfvf = dev; u64 ptrs[NPA_MAX_BURST]; int num_ptrs = 1; dma_addr_t bufptr; /* Refill pool with new buffers */ while (cq->pool_ptrs) { if (otx2_alloc_buffer(pfvf, cq, &bufptr)) { if (num_ptrs--) __cn10k_aura_freeptr(pfvf, cq->cq_idx, ptrs, num_ptrs, cq->rbpool->lmt_addr); break; } cq->pool_ptrs--; ptrs[num_ptrs] = (u64)bufptr + OTX2_HEAD_ROOM; num_ptrs++; if (num_ptrs == NPA_MAX_BURST || cq->pool_ptrs == 0) { __cn10k_aura_freeptr(pfvf, cq->cq_idx, ptrs, num_ptrs, cq->rbpool->lmt_addr); num_ptrs = 1; } } } void cn10k_sqe_flush(void *dev, struct otx2_snd_queue *sq, int size, int qidx) { struct otx2_nic *pfvf = dev; int lmt_id = NIX_LMTID_BASE + (qidx * pfvf->nix_lmt_lines); u64 val = 0, tar_addr = 0; /* FIXME: val[0:10] LMT_ID. * [12:15] no of LMTST - 1 in the burst. * [19:63] data size of each LMTST in the burst except first. */ val = (lmt_id & 0x7FF); /* Target address for LMTST flush tells HW how many 128bit * words are present. * tar_addr[6:4] size of first LMTST - 1 in units of 128b. */ tar_addr |= sq->io_addr | (((size / 16) - 1) & 0x7) << 4; dma_wmb(); memcpy(sq->lmt_addr, sq->sqe_base, size); cn10k_lmt_flush(val, tar_addr); sq->head++; sq->head &= (sq->sqe_cnt - 1); }