// SPDX-License-Identifier: GPL-2.0-only /* Copyright (C) 2020 Marvell. */ #include #include "otx2_cpt_hw_types.h" #include "otx2_cpt_common.h" #include "otx2_cptpf_ucode.h" #include "otx2_cptpf.h" #include "cn10k_cpt.h" #include "rvu_reg.h" #define OTX2_CPT_DRV_NAME "rvu_cptpf" #define OTX2_CPT_DRV_STRING "Marvell RVU CPT Physical Function Driver" static void cptpf_enable_vfpf_mbox_intr(struct otx2_cptpf_dev *cptpf, int num_vfs) { int ena_bits; /* Clear any pending interrupts */ otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFPF_MBOX_INTX(0), ~0x0ULL); otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFPF_MBOX_INTX(1), ~0x0ULL); /* Enable VF interrupts for VFs from 0 to 63 */ ena_bits = ((num_vfs - 1) % 64); otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFPF_MBOX_INT_ENA_W1SX(0), GENMASK_ULL(ena_bits, 0)); if (num_vfs > 64) { /* Enable VF interrupts for VFs from 64 to 127 */ ena_bits = num_vfs - 64 - 1; otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFPF_MBOX_INT_ENA_W1SX(1), GENMASK_ULL(ena_bits, 0)); } } static void cptpf_disable_vfpf_mbox_intr(struct otx2_cptpf_dev *cptpf, int num_vfs) { int vector; /* Disable VF-PF interrupts */ otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFPF_MBOX_INT_ENA_W1CX(0), ~0ULL); otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFPF_MBOX_INT_ENA_W1CX(1), ~0ULL); /* Clear any pending interrupts */ otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFPF_MBOX_INTX(0), ~0ULL); vector = pci_irq_vector(cptpf->pdev, RVU_PF_INT_VEC_VFPF_MBOX0); free_irq(vector, cptpf); if (num_vfs > 64) { otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFPF_MBOX_INTX(1), ~0ULL); vector = pci_irq_vector(cptpf->pdev, RVU_PF_INT_VEC_VFPF_MBOX1); free_irq(vector, cptpf); } } static void cptpf_enable_vf_flr_me_intrs(struct otx2_cptpf_dev *cptpf, int num_vfs) { /* Clear FLR interrupt if any */ otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFFLR_INTX(0), INTR_MASK(num_vfs)); /* Enable VF FLR interrupts */ otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFFLR_INT_ENA_W1SX(0), INTR_MASK(num_vfs)); /* Clear ME interrupt if any */ otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFME_INTX(0), INTR_MASK(num_vfs)); /* Enable VF ME interrupts */ otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFME_INT_ENA_W1SX(0), INTR_MASK(num_vfs)); if (num_vfs <= 64) return; otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFFLR_INTX(1), INTR_MASK(num_vfs - 64)); otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFFLR_INT_ENA_W1SX(1), INTR_MASK(num_vfs - 64)); otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFME_INTX(1), INTR_MASK(num_vfs - 64)); otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFME_INT_ENA_W1SX(1), INTR_MASK(num_vfs - 64)); } static void cptpf_disable_vf_flr_me_intrs(struct otx2_cptpf_dev *cptpf, int num_vfs) { int vector; /* Disable VF FLR interrupts */ otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFFLR_INT_ENA_W1CX(0), INTR_MASK(num_vfs)); vector = pci_irq_vector(cptpf->pdev, RVU_PF_INT_VEC_VFFLR0); free_irq(vector, cptpf); /* Disable VF ME interrupts */ otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFME_INT_ENA_W1CX(0), INTR_MASK(num_vfs)); vector = pci_irq_vector(cptpf->pdev, RVU_PF_INT_VEC_VFME0); free_irq(vector, cptpf); if (num_vfs <= 64) return; otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFFLR_INT_ENA_W1CX(1), INTR_MASK(num_vfs - 64)); vector = pci_irq_vector(cptpf->pdev, RVU_PF_INT_VEC_VFFLR1); free_irq(vector, cptpf); otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFME_INT_ENA_W1CX(1), INTR_MASK(num_vfs - 64)); vector = pci_irq_vector(cptpf->pdev, RVU_PF_INT_VEC_VFME1); free_irq(vector, cptpf); } static void cptpf_flr_wq_handler(struct work_struct *work) { struct cptpf_flr_work *flr_work; struct otx2_cptpf_dev *pf; struct mbox_msghdr *req; struct otx2_mbox *mbox; int vf, reg = 0; flr_work = container_of(work, struct cptpf_flr_work, work); pf = flr_work->pf; mbox = &pf->afpf_mbox; vf = flr_work - pf->flr_work; req = otx2_mbox_alloc_msg_rsp(mbox, 0, sizeof(*req), sizeof(struct msg_rsp)); if (!req) return; req->sig = OTX2_MBOX_REQ_SIG; req->id = MBOX_MSG_VF_FLR; req->pcifunc &= RVU_PFVF_FUNC_MASK; req->pcifunc |= (vf + 1) & RVU_PFVF_FUNC_MASK; otx2_cpt_send_mbox_msg(mbox, pf->pdev); if (vf >= 64) { reg = 1; vf = vf - 64; } /* Clear transaction pending register */ otx2_cpt_write64(pf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFTRPENDX(reg), BIT_ULL(vf)); otx2_cpt_write64(pf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFFLR_INT_ENA_W1SX(reg), BIT_ULL(vf)); } static irqreturn_t cptpf_vf_flr_intr(int __always_unused irq, void *arg) { int reg, dev, vf, start_vf, num_reg = 1; struct otx2_cptpf_dev *cptpf = arg; u64 intr; if (cptpf->max_vfs > 64) num_reg = 2; for (reg = 0; reg < num_reg; reg++) { intr = otx2_cpt_read64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFFLR_INTX(reg)); if (!intr) continue; start_vf = 64 * reg; for (vf = 0; vf < 64; vf++) { if (!(intr & BIT_ULL(vf))) continue; dev = vf + start_vf; queue_work(cptpf->flr_wq, &cptpf->flr_work[dev].work); /* Clear interrupt */ otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFFLR_INTX(reg), BIT_ULL(vf)); /* Disable the interrupt */ otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFFLR_INT_ENA_W1CX(reg), BIT_ULL(vf)); } } return IRQ_HANDLED; } static irqreturn_t cptpf_vf_me_intr(int __always_unused irq, void *arg) { struct otx2_cptpf_dev *cptpf = arg; int reg, vf, num_reg = 1; u64 intr; if (cptpf->max_vfs > 64) num_reg = 2; for (reg = 0; reg < num_reg; reg++) { intr = otx2_cpt_read64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFME_INTX(reg)); if (!intr) continue; for (vf = 0; vf < 64; vf++) { if (!(intr & BIT_ULL(vf))) continue; otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFTRPENDX(reg), BIT_ULL(vf)); /* Clear interrupt */ otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFME_INTX(reg), BIT_ULL(vf)); } } return IRQ_HANDLED; } static void cptpf_unregister_vfpf_intr(struct otx2_cptpf_dev *cptpf, int num_vfs) { cptpf_disable_vfpf_mbox_intr(cptpf, num_vfs); cptpf_disable_vf_flr_me_intrs(cptpf, num_vfs); } static int cptpf_register_vfpf_intr(struct otx2_cptpf_dev *cptpf, int num_vfs) { struct pci_dev *pdev = cptpf->pdev; struct device *dev = &pdev->dev; int ret, vector; vector = pci_irq_vector(pdev, RVU_PF_INT_VEC_VFPF_MBOX0); /* Register VF-PF mailbox interrupt handler */ ret = request_irq(vector, otx2_cptpf_vfpf_mbox_intr, 0, "CPTVFPF Mbox0", cptpf); if (ret) { dev_err(dev, "IRQ registration failed for PFVF mbox0 irq\n"); return ret; } vector = pci_irq_vector(pdev, RVU_PF_INT_VEC_VFFLR0); /* Register VF FLR interrupt handler */ ret = request_irq(vector, cptpf_vf_flr_intr, 0, "CPTPF FLR0", cptpf); if (ret) { dev_err(dev, "IRQ registration failed for VFFLR0 irq\n"); goto free_mbox0_irq; } vector = pci_irq_vector(pdev, RVU_PF_INT_VEC_VFME0); /* Register VF ME interrupt handler */ ret = request_irq(vector, cptpf_vf_me_intr, 0, "CPTPF ME0", cptpf); if (ret) { dev_err(dev, "IRQ registration failed for PFVF mbox0 irq\n"); goto free_flr0_irq; } if (num_vfs > 64) { vector = pci_irq_vector(pdev, RVU_PF_INT_VEC_VFPF_MBOX1); ret = request_irq(vector, otx2_cptpf_vfpf_mbox_intr, 0, "CPTVFPF Mbox1", cptpf); if (ret) { dev_err(dev, "IRQ registration failed for PFVF mbox1 irq\n"); goto free_me0_irq; } vector = pci_irq_vector(pdev, RVU_PF_INT_VEC_VFFLR1); /* Register VF FLR interrupt handler */ ret = request_irq(vector, cptpf_vf_flr_intr, 0, "CPTPF FLR1", cptpf); if (ret) { dev_err(dev, "IRQ registration failed for VFFLR1 irq\n"); goto free_mbox1_irq; } vector = pci_irq_vector(pdev, RVU_PF_INT_VEC_VFME1); /* Register VF FLR interrupt handler */ ret = request_irq(vector, cptpf_vf_me_intr, 0, "CPTPF ME1", cptpf); if (ret) { dev_err(dev, "IRQ registration failed for VFFLR1 irq\n"); goto free_flr1_irq; } } cptpf_enable_vfpf_mbox_intr(cptpf, num_vfs); cptpf_enable_vf_flr_me_intrs(cptpf, num_vfs); return 0; free_flr1_irq: vector = pci_irq_vector(pdev, RVU_PF_INT_VEC_VFFLR1); free_irq(vector, cptpf); free_mbox1_irq: vector = pci_irq_vector(pdev, RVU_PF_INT_VEC_VFPF_MBOX1); free_irq(vector, cptpf); free_me0_irq: vector = pci_irq_vector(pdev, RVU_PF_INT_VEC_VFME0); free_irq(vector, cptpf); free_flr0_irq: vector = pci_irq_vector(pdev, RVU_PF_INT_VEC_VFFLR0); free_irq(vector, cptpf); free_mbox0_irq: vector = pci_irq_vector(pdev, RVU_PF_INT_VEC_VFPF_MBOX0); free_irq(vector, cptpf); return ret; } static void cptpf_flr_wq_destroy(struct otx2_cptpf_dev *pf) { if (!pf->flr_wq) return; destroy_workqueue(pf->flr_wq); pf->flr_wq = NULL; kfree(pf->flr_work); } static int cptpf_flr_wq_init(struct otx2_cptpf_dev *cptpf, int num_vfs) { int vf; cptpf->flr_wq = alloc_ordered_workqueue("cptpf_flr_wq", 0); if (!cptpf->flr_wq) return -ENOMEM; cptpf->flr_work = kcalloc(num_vfs, sizeof(struct cptpf_flr_work), GFP_KERNEL); if (!cptpf->flr_work) goto destroy_wq; for (vf = 0; vf < num_vfs; vf++) { cptpf->flr_work[vf].pf = cptpf; INIT_WORK(&cptpf->flr_work[vf].work, cptpf_flr_wq_handler); } return 0; destroy_wq: destroy_workqueue(cptpf->flr_wq); return -ENOMEM; } static int cptpf_vfpf_mbox_init(struct otx2_cptpf_dev *cptpf, int num_vfs) { struct device *dev = &cptpf->pdev->dev; u64 vfpf_mbox_base; int err, i; cptpf->vfpf_mbox_wq = alloc_workqueue("cpt_vfpf_mailbox", WQ_UNBOUND | WQ_HIGHPRI | WQ_MEM_RECLAIM, 1); if (!cptpf->vfpf_mbox_wq) return -ENOMEM; /* Map VF-PF mailbox memory */ if (test_bit(CN10K_MBOX, &cptpf->cap_flag)) vfpf_mbox_base = readq(cptpf->reg_base + RVU_PF_VF_MBOX_ADDR); else vfpf_mbox_base = readq(cptpf->reg_base + RVU_PF_VF_BAR4_ADDR); if (!vfpf_mbox_base) { dev_err(dev, "VF-PF mailbox address not configured\n"); err = -ENOMEM; goto free_wqe; } cptpf->vfpf_mbox_base = devm_ioremap_wc(dev, vfpf_mbox_base, MBOX_SIZE * cptpf->max_vfs); if (!cptpf->vfpf_mbox_base) { dev_err(dev, "Mapping of VF-PF mailbox address failed\n"); err = -ENOMEM; goto free_wqe; } err = otx2_mbox_init(&cptpf->vfpf_mbox, cptpf->vfpf_mbox_base, cptpf->pdev, cptpf->reg_base, MBOX_DIR_PFVF, num_vfs); if (err) goto free_wqe; for (i = 0; i < num_vfs; i++) { cptpf->vf[i].vf_id = i; cptpf->vf[i].cptpf = cptpf; cptpf->vf[i].intr_idx = i % 64; INIT_WORK(&cptpf->vf[i].vfpf_mbox_work, otx2_cptpf_vfpf_mbox_handler); } return 0; free_wqe: destroy_workqueue(cptpf->vfpf_mbox_wq); return err; } static void cptpf_vfpf_mbox_destroy(struct otx2_cptpf_dev *cptpf) { destroy_workqueue(cptpf->vfpf_mbox_wq); otx2_mbox_destroy(&cptpf->vfpf_mbox); } static void cptpf_disable_afpf_mbox_intr(struct otx2_cptpf_dev *cptpf) { /* Disable AF-PF interrupt */ otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_INT_ENA_W1C, 0x1ULL); /* Clear interrupt if any */ otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_INT, 0x1ULL); } static int cptpf_register_afpf_mbox_intr(struct otx2_cptpf_dev *cptpf) { struct pci_dev *pdev = cptpf->pdev; struct device *dev = &pdev->dev; int ret, irq; irq = pci_irq_vector(pdev, RVU_PF_INT_VEC_AFPF_MBOX); /* Register AF-PF mailbox interrupt handler */ ret = devm_request_irq(dev, irq, otx2_cptpf_afpf_mbox_intr, 0, "CPTAFPF Mbox", cptpf); if (ret) { dev_err(dev, "IRQ registration failed for PFAF mbox irq\n"); return ret; } /* Clear interrupt if any, to avoid spurious interrupts */ otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_INT, 0x1ULL); /* Enable AF-PF interrupt */ otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_INT_ENA_W1S, 0x1ULL); ret = otx2_cpt_send_ready_msg(&cptpf->afpf_mbox, cptpf->pdev); if (ret) { dev_warn(dev, "AF not responding to mailbox, deferring probe\n"); cptpf_disable_afpf_mbox_intr(cptpf); return -EPROBE_DEFER; } return 0; } static int cptpf_afpf_mbox_init(struct otx2_cptpf_dev *cptpf) { struct pci_dev *pdev = cptpf->pdev; resource_size_t offset; int err; cptpf->afpf_mbox_wq = alloc_workqueue("cpt_afpf_mailbox", WQ_UNBOUND | WQ_HIGHPRI | WQ_MEM_RECLAIM, 1); if (!cptpf->afpf_mbox_wq) return -ENOMEM; offset = pci_resource_start(pdev, PCI_MBOX_BAR_NUM); /* Map AF-PF mailbox memory */ cptpf->afpf_mbox_base = devm_ioremap_wc(&pdev->dev, offset, MBOX_SIZE); if (!cptpf->afpf_mbox_base) { dev_err(&pdev->dev, "Unable to map BAR4\n"); err = -ENOMEM; goto error; } err = otx2_mbox_init(&cptpf->afpf_mbox, cptpf->afpf_mbox_base, pdev, cptpf->reg_base, MBOX_DIR_PFAF, 1); if (err) goto error; INIT_WORK(&cptpf->afpf_mbox_work, otx2_cptpf_afpf_mbox_handler); return 0; error: destroy_workqueue(cptpf->afpf_mbox_wq); return err; } static void cptpf_afpf_mbox_destroy(struct otx2_cptpf_dev *cptpf) { destroy_workqueue(cptpf->afpf_mbox_wq); otx2_mbox_destroy(&cptpf->afpf_mbox); } static ssize_t kvf_limits_show(struct device *dev, struct device_attribute *attr, char *buf) { struct otx2_cptpf_dev *cptpf = dev_get_drvdata(dev); return sprintf(buf, "%d\n", cptpf->kvf_limits); } static ssize_t kvf_limits_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct otx2_cptpf_dev *cptpf = dev_get_drvdata(dev); int lfs_num; int ret; ret = kstrtoint(buf, 0, &lfs_num); if (ret) return ret; if (lfs_num < 1 || lfs_num > num_online_cpus()) { dev_err(dev, "lfs count %d must be in range [1 - %d]\n", lfs_num, num_online_cpus()); return -EINVAL; } cptpf->kvf_limits = lfs_num; return count; } static DEVICE_ATTR_RW(kvf_limits); static struct attribute *cptpf_attrs[] = { &dev_attr_kvf_limits.attr, NULL }; static const struct attribute_group cptpf_sysfs_group = { .attrs = cptpf_attrs, }; static int cpt_is_pf_usable(struct otx2_cptpf_dev *cptpf) { u64 rev; rev = otx2_cpt_read64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_BLOCK_ADDRX_DISC(BLKADDR_RVUM)); rev = (rev >> 12) & 0xFF; /* * Check if AF has setup revision for RVUM block, otherwise * driver probe should be deferred until AF driver comes up */ if (!rev) { dev_warn(&cptpf->pdev->dev, "AF is not initialized, deferring probe\n"); return -EPROBE_DEFER; } return 0; } static int cptx_device_reset(struct otx2_cptpf_dev *cptpf, int blkaddr) { int timeout = 10, ret; u64 reg = 0; ret = otx2_cpt_write_af_reg(&cptpf->afpf_mbox, cptpf->pdev, CPT_AF_BLK_RST, 0x1, blkaddr); if (ret) return ret; do { ret = otx2_cpt_read_af_reg(&cptpf->afpf_mbox, cptpf->pdev, CPT_AF_BLK_RST, ®, blkaddr); if (ret) return ret; if (!((reg >> 63) & 0x1)) break; usleep_range(10000, 20000); if (timeout-- < 0) return -EBUSY; } while (1); return ret; } static int cptpf_device_reset(struct otx2_cptpf_dev *cptpf) { int ret = 0; if (cptpf->has_cpt1) { ret = cptx_device_reset(cptpf, BLKADDR_CPT1); if (ret) return ret; } return cptx_device_reset(cptpf, BLKADDR_CPT0); } static void cptpf_check_block_implemented(struct otx2_cptpf_dev *cptpf) { u64 cfg; cfg = otx2_cpt_read64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_BLOCK_ADDRX_DISC(BLKADDR_CPT1)); if (cfg & BIT_ULL(11)) cptpf->has_cpt1 = true; } static int cptpf_device_init(struct otx2_cptpf_dev *cptpf) { union otx2_cptx_af_constants1 af_cnsts1 = {0}; int ret = 0; /* check if 'implemented' bit is set for block BLKADDR_CPT1 */ cptpf_check_block_implemented(cptpf); /* Reset the CPT PF device */ ret = cptpf_device_reset(cptpf); if (ret) return ret; /* Get number of SE, IE and AE engines */ ret = otx2_cpt_read_af_reg(&cptpf->afpf_mbox, cptpf->pdev, CPT_AF_CONSTANTS1, &af_cnsts1.u, BLKADDR_CPT0); if (ret) return ret; cptpf->eng_grps.avail.max_se_cnt = af_cnsts1.s.se; cptpf->eng_grps.avail.max_ie_cnt = af_cnsts1.s.ie; cptpf->eng_grps.avail.max_ae_cnt = af_cnsts1.s.ae; /* Disable all cores */ ret = otx2_cpt_disable_all_cores(cptpf); return ret; } static int cptpf_sriov_disable(struct pci_dev *pdev) { struct otx2_cptpf_dev *cptpf = pci_get_drvdata(pdev); int num_vfs = pci_num_vf(pdev); if (!num_vfs) return 0; pci_disable_sriov(pdev); cptpf_unregister_vfpf_intr(cptpf, num_vfs); cptpf_flr_wq_destroy(cptpf); cptpf_vfpf_mbox_destroy(cptpf); module_put(THIS_MODULE); cptpf->enabled_vfs = 0; return 0; } static int cptpf_sriov_enable(struct pci_dev *pdev, int num_vfs) { struct otx2_cptpf_dev *cptpf = pci_get_drvdata(pdev); int ret; /* Initialize VF<=>PF mailbox */ ret = cptpf_vfpf_mbox_init(cptpf, num_vfs); if (ret) return ret; ret = cptpf_flr_wq_init(cptpf, num_vfs); if (ret) goto destroy_mbox; /* Register VF<=>PF mailbox interrupt */ ret = cptpf_register_vfpf_intr(cptpf, num_vfs); if (ret) goto destroy_flr; /* Get CPT HW capabilities using LOAD_FVC operation. */ ret = otx2_cpt_discover_eng_capabilities(cptpf); if (ret) goto disable_intr; ret = otx2_cpt_create_eng_grps(cptpf, &cptpf->eng_grps); if (ret) goto disable_intr; cptpf->enabled_vfs = num_vfs; ret = pci_enable_sriov(pdev, num_vfs); if (ret) goto disable_intr; dev_notice(&cptpf->pdev->dev, "VFs enabled: %d\n", num_vfs); try_module_get(THIS_MODULE); return num_vfs; disable_intr: cptpf_unregister_vfpf_intr(cptpf, num_vfs); cptpf->enabled_vfs = 0; destroy_flr: cptpf_flr_wq_destroy(cptpf); destroy_mbox: cptpf_vfpf_mbox_destroy(cptpf); return ret; } static int otx2_cptpf_sriov_configure(struct pci_dev *pdev, int num_vfs) { if (num_vfs > 0) { return cptpf_sriov_enable(pdev, num_vfs); } else { return cptpf_sriov_disable(pdev); } } static int otx2_cptpf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct device *dev = &pdev->dev; struct otx2_cptpf_dev *cptpf; int err; cptpf = devm_kzalloc(dev, sizeof(*cptpf), GFP_KERNEL); if (!cptpf) return -ENOMEM; err = pcim_enable_device(pdev); if (err) { dev_err(dev, "Failed to enable PCI device\n"); goto clear_drvdata; } err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48)); if (err) { dev_err(dev, "Unable to get usable DMA configuration\n"); goto clear_drvdata; } /* Map PF's configuration registers */ err = pcim_iomap_regions_request_all(pdev, 1 << PCI_PF_REG_BAR_NUM, OTX2_CPT_DRV_NAME); if (err) { dev_err(dev, "Couldn't get PCI resources 0x%x\n", err); goto clear_drvdata; } pci_set_master(pdev); pci_set_drvdata(pdev, cptpf); cptpf->pdev = pdev; cptpf->reg_base = pcim_iomap_table(pdev)[PCI_PF_REG_BAR_NUM]; /* Check if AF driver is up, otherwise defer probe */ err = cpt_is_pf_usable(cptpf); if (err) goto clear_drvdata; err = pci_alloc_irq_vectors(pdev, RVU_PF_INT_VEC_CNT, RVU_PF_INT_VEC_CNT, PCI_IRQ_MSIX); if (err < 0) { dev_err(dev, "Request for %d msix vectors failed\n", RVU_PF_INT_VEC_CNT); goto clear_drvdata; } otx2_cpt_set_hw_caps(pdev, &cptpf->cap_flag); /* Initialize AF-PF mailbox */ err = cptpf_afpf_mbox_init(cptpf); if (err) goto clear_drvdata; /* Register mailbox interrupt */ err = cptpf_register_afpf_mbox_intr(cptpf); if (err) goto destroy_afpf_mbox; cptpf->max_vfs = pci_sriov_get_totalvfs(pdev); err = cn10k_cptpf_lmtst_init(cptpf); if (err) goto unregister_intr; /* Initialize CPT PF device */ err = cptpf_device_init(cptpf); if (err) goto unregister_intr; /* Initialize engine groups */ err = otx2_cpt_init_eng_grps(pdev, &cptpf->eng_grps); if (err) goto unregister_intr; err = sysfs_create_group(&dev->kobj, &cptpf_sysfs_group); if (err) goto cleanup_eng_grps; return 0; cleanup_eng_grps: otx2_cpt_cleanup_eng_grps(pdev, &cptpf->eng_grps); unregister_intr: cptpf_disable_afpf_mbox_intr(cptpf); destroy_afpf_mbox: cptpf_afpf_mbox_destroy(cptpf); clear_drvdata: pci_set_drvdata(pdev, NULL); return err; } static void otx2_cptpf_remove(struct pci_dev *pdev) { struct otx2_cptpf_dev *cptpf = pci_get_drvdata(pdev); if (!cptpf) return; cptpf_sriov_disable(pdev); /* Delete sysfs entry created for kernel VF limits */ sysfs_remove_group(&pdev->dev.kobj, &cptpf_sysfs_group); /* Cleanup engine groups */ otx2_cpt_cleanup_eng_grps(pdev, &cptpf->eng_grps); /* Disable AF-PF mailbox interrupt */ cptpf_disable_afpf_mbox_intr(cptpf); /* Destroy AF-PF mbox */ cptpf_afpf_mbox_destroy(cptpf); pci_set_drvdata(pdev, NULL); } /* Supported devices */ static const struct pci_device_id otx2_cpt_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OTX2_CPT_PCI_PF_DEVICE_ID) }, { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, CN10K_CPT_PCI_PF_DEVICE_ID) }, { 0, } /* end of table */ }; static struct pci_driver otx2_cpt_pci_driver = { .name = OTX2_CPT_DRV_NAME, .id_table = otx2_cpt_id_table, .probe = otx2_cptpf_probe, .remove = otx2_cptpf_remove, .sriov_configure = otx2_cptpf_sriov_configure }; module_pci_driver(otx2_cpt_pci_driver); MODULE_AUTHOR("Marvell"); MODULE_DESCRIPTION(OTX2_CPT_DRV_STRING); MODULE_LICENSE("GPL v2"); MODULE_DEVICE_TABLE(pci, otx2_cpt_id_table);