From ed135040f0abe9d5665c77e97df7811365c8764e Mon Sep 17 00:00:00 2001 From: Archana Muniganti Date: Fri, 25 Jun 2021 11:06:38 +0530 Subject: [PATCH] common/cnxk: add CPT LF configuration Add routines to init & fini CPT LFs. CPT LFs are queues to the hardware enabling instruction submissions. Signed-off-by: Anoob Joseph Signed-off-by: Archana Muniganti Signed-off-by: Vidya Sagar Velumuri Acked-by: Akhil Goyal --- drivers/common/cnxk/roc_cpt.c | 357 +++++++++++++++++++++++++++++ drivers/common/cnxk/roc_cpt.h | 20 ++ drivers/common/cnxk/roc_cpt_priv.h | 2 + drivers/common/cnxk/version.map | 3 + 4 files changed, 382 insertions(+) diff --git a/drivers/common/cnxk/roc_cpt.c b/drivers/common/cnxk/roc_cpt.c index e723ee7f84..02062c1bf7 100644 --- a/drivers/common/cnxk/roc_cpt.c +++ b/drivers/common/cnxk/roc_cpt.c @@ -5,6 +5,189 @@ #include "roc_api.h" #include "roc_priv.h" +#define CPT_IQ_FC_LEN 128 +#define CPT_IQ_GRP_LEN 16 + +#define CPT_IQ_NB_DESC_MULTIPLIER 40 + +/* The effective queue size to software is (CPT_LF_Q_SIZE[SIZE_DIV40] - 1 - 8). + * + * CPT requires 320 free entries (+8). And 40 entries are required for + * allowing CPT to discard packet when the queues are full (+1). + */ +#define CPT_IQ_NB_DESC_SIZE_DIV40(nb_desc) \ + (PLT_DIV_CEIL(nb_desc, CPT_IQ_NB_DESC_MULTIPLIER) + 1 + 8) + +#define CPT_IQ_GRP_SIZE(nb_desc) \ + (CPT_IQ_NB_DESC_SIZE_DIV40(nb_desc) * CPT_IQ_GRP_LEN) + +#define CPT_LF_MAX_NB_DESC 128000 +#define CPT_LF_DEFAULT_NB_DESC 1024 + +static void +cpt_lf_misc_intr_enb_dis(struct roc_cpt_lf *lf, bool enb) +{ + /* Enable all cpt lf error irqs except RQ_DISABLED and CQ_DISABLED */ + if (enb) + plt_write64((BIT_ULL(6) | BIT_ULL(5) | BIT_ULL(3) | BIT_ULL(2) | + BIT_ULL(1)), + lf->rbase + CPT_LF_MISC_INT_ENA_W1S); + else + plt_write64((BIT_ULL(6) | BIT_ULL(5) | BIT_ULL(3) | BIT_ULL(2) | + BIT_ULL(1)), + lf->rbase + CPT_LF_MISC_INT_ENA_W1C); +} + +static void +cpt_lf_misc_irq(void *param) +{ + struct roc_cpt_lf *lf = (struct roc_cpt_lf *)param; + struct dev *dev = lf->dev; + uint64_t intr; + + intr = plt_read64(lf->rbase + CPT_LF_MISC_INT); + if (intr == 0) + return; + + plt_err("Err_irq=0x%" PRIx64 " pf=%d, vf=%d", intr, dev->pf, dev->vf); + + /* Clear interrupt */ + plt_write64(intr, lf->rbase + CPT_LF_MISC_INT); +} + +static int +cpt_lf_register_misc_irq(struct roc_cpt_lf *lf) +{ + struct plt_pci_device *pci_dev = lf->pci_dev; + struct plt_intr_handle *handle; + int rc, vec; + + handle = &pci_dev->intr_handle; + + vec = lf->msixoff + CPT_LF_INT_VEC_MISC; + /* Clear err interrupt */ + cpt_lf_misc_intr_enb_dis(lf, false); + /* Set used interrupt vectors */ + rc = dev_irq_register(handle, cpt_lf_misc_irq, lf, vec); + /* Enable all dev interrupt except for RQ_DISABLED */ + cpt_lf_misc_intr_enb_dis(lf, true); + + return rc; +} + +static void +cpt_lf_unregister_misc_irq(struct roc_cpt_lf *lf) +{ + struct plt_pci_device *pci_dev = lf->pci_dev; + struct plt_intr_handle *handle; + int vec; + + handle = &pci_dev->intr_handle; + + vec = lf->msixoff + CPT_LF_INT_VEC_MISC; + /* Clear err interrupt */ + cpt_lf_misc_intr_enb_dis(lf, false); + dev_irq_unregister(handle, cpt_lf_misc_irq, lf, vec); +} + +static void +cpt_lf_done_intr_enb_dis(struct roc_cpt_lf *lf, bool enb) +{ + if (enb) + plt_write64(0x1, lf->rbase + CPT_LF_DONE_INT_ENA_W1S); + else + plt_write64(0x1, lf->rbase + CPT_LF_DONE_INT_ENA_W1C); +} + +static void +cpt_lf_done_irq(void *param) +{ + struct roc_cpt_lf *lf = param; + uint64_t done_wait; + uint64_t intr; + + /* Read the number of completed requests */ + intr = plt_read64(lf->rbase + CPT_LF_DONE); + if (intr == 0) + return; + + done_wait = plt_read64(lf->rbase + CPT_LF_DONE_WAIT); + + /* Acknowledge the number of completed requests */ + plt_write64(intr, lf->rbase + CPT_LF_DONE_ACK); + + plt_write64(done_wait, lf->rbase + CPT_LF_DONE_WAIT); +} + +static int +cpt_lf_register_done_irq(struct roc_cpt_lf *lf) +{ + struct plt_pci_device *pci_dev = lf->pci_dev; + struct plt_intr_handle *handle; + int rc, vec; + + handle = &pci_dev->intr_handle; + + vec = lf->msixoff + CPT_LF_INT_VEC_DONE; + + /* Clear done interrupt */ + cpt_lf_done_intr_enb_dis(lf, false); + + /* Set used interrupt vectors */ + rc = dev_irq_register(handle, cpt_lf_done_irq, lf, vec); + + /* Enable done interrupt */ + cpt_lf_done_intr_enb_dis(lf, true); + + return rc; +} + +static void +cpt_lf_unregister_done_irq(struct roc_cpt_lf *lf) +{ + struct plt_pci_device *pci_dev = lf->pci_dev; + struct plt_intr_handle *handle; + int vec; + + handle = &pci_dev->intr_handle; + + vec = lf->msixoff + CPT_LF_INT_VEC_DONE; + + /* Clear done interrupt */ + cpt_lf_done_intr_enb_dis(lf, false); + dev_irq_unregister(handle, cpt_lf_done_irq, lf, vec); +} + +static int +cpt_lf_register_irqs(struct roc_cpt_lf *lf) +{ + int rc; + + if (lf->msixoff == MSIX_VECTOR_INVALID) { + plt_err("Invalid CPTLF MSIX vector offset vector: 0x%x", + lf->msixoff); + return -EINVAL; + } + + /* Register lf err interrupt */ + rc = cpt_lf_register_misc_irq(lf); + if (rc) + plt_err("Error registering IRQs"); + + rc = cpt_lf_register_done_irq(lf); + if (rc) + plt_err("Error registering IRQs"); + + return rc; +} + +static void +cpt_lf_unregister_irqs(struct roc_cpt_lf *lf) +{ + cpt_lf_unregister_misc_irq(lf); + cpt_lf_unregister_done_irq(lf); +} + int roc_cpt_rxc_time_cfg(struct roc_cpt *roc_cpt, struct roc_cpt_rxc_time_cfg *cfg) { @@ -146,6 +329,69 @@ cpt_hardware_caps_get(struct dev *dev, union cpt_eng_caps *hw_caps) return 0; } +static uint32_t +cpt_lf_iq_mem_calc(uint32_t nb_desc) +{ + uint32_t len; + + /* Space for instruction group memory */ + len = CPT_IQ_GRP_SIZE(nb_desc); + + /* Align to 128B */ + len = PLT_ALIGN(len, ROC_ALIGN); + + /* Space for FC */ + len += CPT_IQ_FC_LEN; + + /* For instruction queues */ + len += CPT_IQ_NB_DESC_SIZE_DIV40(nb_desc) * CPT_IQ_NB_DESC_MULTIPLIER * + sizeof(struct cpt_inst_s); + + return len; +} + +static inline void +cpt_iq_init(struct roc_cpt_lf *lf) +{ + union cpt_lf_q_size lf_q_size = {.u = 0x0}; + union cpt_lf_q_base lf_q_base = {.u = 0x0}; + union cpt_lf_inprog lf_inprog; + union cpt_lf_ctl lf_ctl; + uintptr_t addr; + + lf->io_addr = lf->rbase + CPT_LF_NQX(0); + + /* Disable command queue */ + roc_cpt_iq_disable(lf); + + /* Set command queue base address */ + addr = (uintptr_t)lf->iq_vaddr + + PLT_ALIGN(CPT_IQ_GRP_SIZE(lf->nb_desc), ROC_ALIGN); + + lf_q_base.u = addr; + + plt_write64(lf_q_base.u, lf->rbase + CPT_LF_Q_BASE); + + /* Set command queue size */ + lf_q_size.s.size_div40 = CPT_IQ_NB_DESC_SIZE_DIV40(lf->nb_desc); + plt_write64(lf_q_size.u, lf->rbase + CPT_LF_Q_SIZE); + + /* Enable command queue execution */ + lf_inprog.u = plt_read64(lf->rbase + CPT_LF_INPROG); + lf_inprog.s.eena = 1; + plt_write64(lf_inprog.u, lf->rbase + CPT_LF_INPROG); + + /* Enable instruction queue enqueuing */ + lf_ctl.u = plt_read64(lf->rbase + CPT_LF_CTL); + lf_ctl.s.ena = 1; + lf_ctl.s.fc_ena = 1; + lf_ctl.s.fc_up_crossing = 1; + lf_ctl.s.fc_hyst_bits = CPT_FC_NUM_HYST_BITS; + plt_write64(lf_ctl.u, lf->rbase + CPT_LF_CTL); + + lf->fc_addr = (uint64_t *)addr; +} + int roc_cpt_dev_configure(struct roc_cpt *roc_cpt, int nb_lf) { @@ -209,6 +455,63 @@ cpt_get_blkaddr(struct dev *dev) return reg & 0x1FFULL ? RVU_BLOCK_ADDR_CPT1 : RVU_BLOCK_ADDR_CPT0; } +int +cpt_lf_init(struct roc_cpt_lf *lf) +{ + struct dev *dev = lf->dev; + uint64_t blkaddr; + void *iq_mem; + int rc; + + if (lf->nb_desc == 0 || lf->nb_desc > CPT_LF_MAX_NB_DESC) + lf->nb_desc = CPT_LF_DEFAULT_NB_DESC; + + /* Allocate memory for instruction queue for CPT LF. */ + iq_mem = plt_zmalloc(cpt_lf_iq_mem_calc(lf->nb_desc), ROC_ALIGN); + if (iq_mem == NULL) + return -ENOMEM; + + blkaddr = cpt_get_blkaddr(dev); + lf->rbase = dev->bar2 + ((blkaddr << 20) | (lf->lf_id << 12)); + lf->iq_vaddr = iq_mem; + lf->lmt_base = dev->lmt_base; + lf->pf_func = dev->pf_func; + + /* Initialize instruction queue */ + cpt_iq_init(lf); + + rc = cpt_lf_register_irqs(lf); + if (rc) + goto disable_iq; + + return 0; + +disable_iq: + roc_cpt_iq_disable(lf); + plt_free(iq_mem); + return rc; +} + +int +roc_cpt_lf_init(struct roc_cpt *roc_cpt, struct roc_cpt_lf *lf) +{ + struct cpt *cpt = roc_cpt_to_cpt_priv(roc_cpt); + int rc; + + lf->dev = &cpt->dev; + lf->roc_cpt = roc_cpt; + lf->msixoff = cpt->lf_msix_off[lf->lf_id]; + lf->pci_dev = cpt->pci_dev; + + rc = cpt_lf_init(lf); + if (rc) + return rc; + + /* LF init successful */ + roc_cpt->lf[lf->lf_id] = lf; + return rc; +} + int roc_cpt_dev_init(struct roc_cpt *roc_cpt) { @@ -267,6 +570,29 @@ fail: return rc; } +void +cpt_lf_fini(struct roc_cpt_lf *lf) +{ + /* Unregister IRQ's */ + cpt_lf_unregister_irqs(lf); + + /* Disable IQ */ + roc_cpt_iq_disable(lf); + + /* Free memory */ + plt_free(lf->iq_vaddr); + lf->iq_vaddr = NULL; +} + +void +roc_cpt_lf_fini(struct roc_cpt_lf *lf) +{ + if (lf == NULL) + return; + lf->roc_cpt->lf[lf->lf_id] = NULL; + cpt_lf_fini(lf); +} + int roc_cpt_dev_fini(struct roc_cpt *roc_cpt) { @@ -341,3 +667,34 @@ roc_cpt_eng_grp_add(struct roc_cpt *roc_cpt, enum cpt_eng_type eng_type) return rsp->eng_grp_num; } + +void +roc_cpt_iq_disable(struct roc_cpt_lf *lf) +{ + union cpt_lf_ctl lf_ctl = {.u = 0x0}; + union cpt_lf_inprog lf_inprog; + int timeout = 20; + + /* Disable instructions enqueuing */ + plt_write64(lf_ctl.u, lf->rbase + CPT_LF_CTL); + + /* Wait for instruction queue to become empty */ + do { + lf_inprog.u = plt_read64(lf->rbase + CPT_LF_INPROG); + if (!lf_inprog.s.inflight) + break; + + plt_delay_ms(20); + if (timeout-- < 0) { + plt_err("CPT LF %d is still busy", lf->lf_id); + break; + } + + } while (1); + + /* Disable executions in the LF's queue. + * The queue should be empty at this point + */ + lf_inprog.s.eena = 0x0; + plt_write64(lf_inprog.u, lf->rbase + CPT_LF_INPROG); +} diff --git a/drivers/common/cnxk/roc_cpt.h b/drivers/common/cnxk/roc_cpt.h index bae472f060..e258ca51d7 100644 --- a/drivers/common/cnxk/roc_cpt.h +++ b/drivers/common/cnxk/roc_cpt.h @@ -14,6 +14,23 @@ #define ROC_CPT_MAX_LFS 64 +struct roc_cpt_lf { + /* Input parameters */ + uint16_t lf_id; + uint32_t nb_desc; + /* End of Input parameters */ + struct plt_pci_device *pci_dev; + struct dev *dev; + struct roc_cpt *roc_cpt; + uintptr_t rbase; + uintptr_t lmt_base; + uint16_t msixoff; + uint16_t pf_func; + uint64_t *fc_addr; + uint64_t io_addr; + uint8_t *iq_vaddr; +} __plt_cache_aligned; + struct roc_cpt { struct plt_pci_device *pci_dev; struct roc_cpt_lf *lf[ROC_CPT_MAX_LFS]; @@ -44,4 +61,7 @@ int __roc_api roc_cpt_eng_grp_add(struct roc_cpt *roc_cpt, enum cpt_eng_type eng_type); int __roc_api roc_cpt_dev_configure(struct roc_cpt *roc_cpt, int nb_lf); void __roc_api roc_cpt_dev_clear(struct roc_cpt *roc_cpt); +int __roc_api roc_cpt_lf_init(struct roc_cpt *roc_cpt, struct roc_cpt_lf *lf); +void __roc_api roc_cpt_lf_fini(struct roc_cpt_lf *lf); +void __roc_api roc_cpt_iq_disable(struct roc_cpt_lf *lf); #endif /* _ROC_CPT_H_ */ diff --git a/drivers/common/cnxk/roc_cpt_priv.h b/drivers/common/cnxk/roc_cpt_priv.h index 0ef6774792..6cfa4dff43 100644 --- a/drivers/common/cnxk/roc_cpt_priv.h +++ b/drivers/common/cnxk/roc_cpt_priv.h @@ -30,6 +30,8 @@ int cpt_lfs_detach(struct dev *dev); int cpt_lfs_alloc(struct dev *dev, uint8_t eng_grpmsk, uint8_t blk, bool inl_dev_sso); int cpt_lfs_free(struct dev *dev); +int cpt_lf_init(struct roc_cpt_lf *lf); +void cpt_lf_fini(struct roc_cpt_lf *lf); int cpt_get_msix_offset(struct dev *dev, struct msix_offset_rsp **msix_rsp); uint64_t cpt_get_blkaddr(struct dev *dev); diff --git a/drivers/common/cnxk/version.map b/drivers/common/cnxk/version.map index 8699ea8cb1..f2828187d5 100644 --- a/drivers/common/cnxk/version.map +++ b/drivers/common/cnxk/version.map @@ -38,6 +38,9 @@ INTERNAL { roc_cpt_dev_fini; roc_cpt_dev_init; roc_cpt_eng_grp_add; + roc_cpt_iq_disable; + roc_cpt_lf_init; + roc_cpt_lf_fini; roc_cpt_rxc_time_cfg; roc_error_msg_get; roc_idev_cpt_get; -- 2.20.1