ci: enable unit test for aarch64
[dpdk.git] / drivers / common / octeontx2 / otx2_dev.c
index 0994385..d61c712 100644 (file)
@@ -51,6 +51,52 @@ mbox_mem_unmap(void *va, size_t size)
                munmap(va, size);
 }
 
+static int
+pf_af_sync_msg(struct otx2_dev *dev, struct mbox_msghdr **rsp)
+{
+       uint32_t timeout = 0, sleep = 1; struct otx2_mbox *mbox = dev->mbox;
+       struct otx2_mbox_dev *mdev = &mbox->dev[0];
+       volatile uint64_t int_status;
+       struct mbox_msghdr *msghdr;
+       uint64_t off;
+       int rc = 0;
+
+       /* We need to disable PF interrupts. We are in timer interrupt */
+       otx2_write64(~0ull, dev->bar2 + RVU_PF_INT_ENA_W1C);
+
+       /* Send message */
+       otx2_mbox_msg_send(mbox, 0);
+
+       do {
+               rte_delay_ms(sleep);
+               timeout += sleep;
+               if (timeout >= MBOX_RSP_TIMEOUT) {
+                       otx2_err("Message timeout: %dms", MBOX_RSP_TIMEOUT);
+                       rc = -EIO;
+                       break;
+               }
+               int_status = otx2_read64(dev->bar2 + RVU_PF_INT);
+       } while ((int_status & 0x1) != 0x1);
+
+       /* Clear */
+       otx2_write64(int_status, dev->bar2 + RVU_PF_INT);
+
+       /* Enable interrupts */
+       otx2_write64(~0ull, dev->bar2 + RVU_PF_INT_ENA_W1S);
+
+       if (rc == 0) {
+               /* Get message */
+               off = mbox->rx_start +
+                       RTE_ALIGN(sizeof(struct mbox_hdr), MBOX_MSG_ALIGN);
+               msghdr = (struct mbox_msghdr *)((uintptr_t)mdev->mbase + off);
+               if (rsp)
+                       *rsp = msghdr;
+               rc = msghdr->rc;
+       }
+
+       return rc;
+}
+
 static int
 af_pf_wait_msg(struct otx2_dev *dev, uint16_t vf, int num_msg)
 {
@@ -531,17 +577,16 @@ otx2_pf_vf_mbox_irq(void *param)
 
        intr = otx2_read64(dev->bar2 + RVU_VF_INT);
        if (intr == 0)
-               return;
+               otx2_base_dbg("Proceeding to check mbox UP messages if any");
 
        otx2_write64(intr, dev->bar2 + RVU_VF_INT);
        otx2_base_dbg("Irq 0x%" PRIx64 "(pf:%d,vf:%d)", intr, dev->pf, dev->vf);
-       if (intr) {
-               /* First process all configuration messages */
-               otx2_process_msgs(dev, dev->mbox);
 
-               /* Process Uplink messages */
-               otx2_process_msgs_up(dev, &dev->mbox_up);
-       }
+       /* First process all configuration messages */
+       otx2_process_msgs(dev, dev->mbox);
+
+       /* Process Uplink messages */
+       otx2_process_msgs_up(dev, &dev->mbox_up);
 }
 
 static void
@@ -552,18 +597,16 @@ otx2_af_pf_mbox_irq(void *param)
 
        intr = otx2_read64(dev->bar2 + RVU_PF_INT);
        if (intr == 0)
-               return;
+               otx2_base_dbg("Proceeding to check mbox UP messages if any");
 
        otx2_write64(intr, dev->bar2 + RVU_PF_INT);
-
        otx2_base_dbg("Irq 0x%" PRIx64 "(pf:%d,vf:%d)", intr, dev->pf, dev->vf);
-       if (intr) {
-               /* First process all configuration messages */
-               otx2_process_msgs(dev, dev->mbox);
 
-               /* Process Uplink messages */
-               otx2_process_msgs_up(dev, &dev->mbox_up);
-       }
+       /* First process all configuration messages */
+       otx2_process_msgs(dev, dev->mbox);
+
+       /* Process Uplink messages */
+       otx2_process_msgs_up(dev, &dev->mbox_up);
 }
 
 static int
@@ -698,25 +741,139 @@ static void
 mbox_unregister_irq(struct rte_pci_device *pci_dev, struct otx2_dev *dev)
 {
        if (otx2_dev_is_vf(dev))
-               return mbox_unregister_vf_irq(pci_dev, dev);
+               mbox_unregister_vf_irq(pci_dev, dev);
        else
-               return mbox_unregister_pf_irq(pci_dev, dev);
+               mbox_unregister_pf_irq(pci_dev, dev);
+}
+
+static int
+vf_flr_send_msg(struct otx2_dev *dev, uint16_t vf)
+{
+       struct otx2_mbox *mbox = dev->mbox;
+       struct msg_req *req;
+       int rc;
+
+       req = otx2_mbox_alloc_msg_vf_flr(mbox);
+       /* Overwrite pcifunc to indicate VF */
+       req->hdr.pcifunc = otx2_pfvf_func(dev->pf, vf);
+
+       /* Sync message in interrupt context */
+       rc = pf_af_sync_msg(dev, NULL);
+       if (rc)
+               otx2_err("Failed to send VF FLR mbox msg, rc=%d", rc);
+
+       return rc;
 }
 
 static void
-otx2_update_pass_hwcap(struct rte_pci_device *pci_dev, struct otx2_dev *dev)
+otx2_pf_vf_flr_irq(void *param)
 {
-       RTE_SET_USED(pci_dev);
+       struct otx2_dev *dev = (struct otx2_dev *)param;
+       uint16_t max_vf = 64, vf;
+       uintptr_t bar2;
+       uint64_t intr;
+       int i;
+
+       max_vf = (dev->maxvf > 0) ? dev->maxvf : 64;
+       bar2 = dev->bar2;
+
+       otx2_base_dbg("FLR VF interrupt: max_vf: %d", max_vf);
+
+       for (i = 0; i < MAX_VFPF_DWORD_BITS; ++i) {
+               intr = otx2_read64(bar2 + RVU_PF_VFFLR_INTX(i));
+               if (!intr)
+                       continue;
+
+               for (vf = 0; vf < max_vf; vf++) {
+                       if (!(intr & (1ULL << vf)))
+                               continue;
+
+                       otx2_base_dbg("FLR: i :%d intr: 0x%" PRIx64 ", vf-%d",
+                                     i, intr, (64 * i + vf));
+                       /* Clear interrupt */
+                       otx2_write64(BIT_ULL(vf), bar2 + RVU_PF_VFFLR_INTX(i));
+                       /* Disable the interrupt */
+                       otx2_write64(BIT_ULL(vf),
+                                    bar2 + RVU_PF_VFFLR_INT_ENA_W1CX(i));
+                       /* Inform AF about VF reset */
+                       vf_flr_send_msg(dev, vf);
+
+                       /* Signal FLR finish */
+                       otx2_write64(BIT_ULL(vf), bar2 + RVU_PF_VFTRPENDX(i));
+                       /* Enable interrupt */
+                       otx2_write64(~0ull,
+                                    bar2 + RVU_PF_VFFLR_INT_ENA_W1SX(i));
+               }
+       }
+}
+
+static int
+vf_flr_unregister_irqs(struct rte_pci_device *pci_dev, struct otx2_dev *dev)
+{
+       struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+       int i;
+
+       otx2_base_dbg("Unregister VF FLR interrupts for %s", pci_dev->name);
+
+       /* HW clear irq */
+       for (i = 0; i < MAX_VFPF_DWORD_BITS; i++)
+               otx2_write64(~0ull, dev->bar2 + RVU_PF_VFFLR_INT_ENA_W1CX(i));
+
+       otx2_unregister_irq(intr_handle, otx2_pf_vf_flr_irq, dev,
+                           RVU_PF_INT_VEC_VFFLR0);
+
+       otx2_unregister_irq(intr_handle, otx2_pf_vf_flr_irq, dev,
+                           RVU_PF_INT_VEC_VFFLR1);
+
+       return 0;
+}
+
+static int
+vf_flr_register_irqs(struct rte_pci_device *pci_dev, struct otx2_dev *dev)
+{
+       struct rte_intr_handle *handle = &pci_dev->intr_handle;
+       int i, rc;
+
+       otx2_base_dbg("Register VF FLR interrupts for %s", pci_dev->name);
+
+       rc = otx2_register_irq(handle, otx2_pf_vf_flr_irq, dev,
+                              RVU_PF_INT_VEC_VFFLR0);
+       if (rc)
+               otx2_err("Failed to init RVU_PF_INT_VEC_VFFLR0 rc=%d", rc);
+
+       rc = otx2_register_irq(handle, otx2_pf_vf_flr_irq, dev,
+                              RVU_PF_INT_VEC_VFFLR1);
+       if (rc)
+               otx2_err("Failed to init RVU_PF_INT_VEC_VFFLR1 rc=%d", rc);
+
+       /* Enable HW interrupt */
+       for (i = 0; i < MAX_VFPF_DWORD_BITS; ++i) {
+               otx2_write64(~0ull, dev->bar2 + RVU_PF_VFFLR_INTX(i));
+               otx2_write64(~0ull, dev->bar2 + RVU_PF_VFTRPENDX(i));
+               otx2_write64(~0ull, dev->bar2 + RVU_PF_VFFLR_INT_ENA_W1SX(i));
+       }
+       return 0;
+}
 
-       /* Update this logic when we have A1 */
-       dev->hwcap |= OTX2_HWCAP_F_A0;
+/**
+ * @internal
+ * Get number of active VFs for the given PF device.
+ */
+int
+otx2_dev_active_vfs(void *otx2_dev)
+{
+       struct otx2_dev *dev = otx2_dev;
+       int i, count = 0;
+
+       for (i = 0; i < MAX_VFPF_DWORD_BITS; i++)
+               count += __builtin_popcount(dev->active_vfs[i]);
+
+       return count;
 }
 
 static void
 otx2_update_vf_hwcap(struct rte_pci_device *pci_dev, struct otx2_dev *dev)
 {
-       dev->hwcap = 0;
-
        switch (pci_dev->id.device_id) {
        case PCI_DEVID_OCTEONTX2_RVU_PF:
                break;
@@ -725,6 +882,7 @@ otx2_update_vf_hwcap(struct rte_pci_device *pci_dev, struct otx2_dev *dev)
        case PCI_DEVID_OCTEONTX2_RVU_CPT_VF:
        case PCI_DEVID_OCTEONTX2_RVU_AF_VF:
        case PCI_DEVID_OCTEONTX2_RVU_VF:
+       case PCI_DEVID_OCTEONTX2_RVU_SDP_VF:
                dev->hwcap |= OTX2_HWCAP_F_VF;
                break;
        }
@@ -735,10 +893,11 @@ otx2_update_vf_hwcap(struct rte_pci_device *pci_dev, struct otx2_dev *dev)
  * Initialize the otx2 device
  */
 int
-otx2_dev_init(struct rte_pci_device *pci_dev, void *otx2_dev)
+otx2_dev_priv_init(struct rte_pci_device *pci_dev, void *otx2_dev)
 {
        int up_direction = MBOX_DIR_PFAF_UP;
        int rc, direction = MBOX_DIR_PFAF;
+       uint64_t intr_offset = RVU_PF_INT;
        struct otx2_dev *dev = otx2_dev;
        uintptr_t bar2, bar4;
        uint64_t bar4_addr;
@@ -759,20 +918,22 @@ otx2_dev_init(struct rte_pci_device *pci_dev, void *otx2_dev)
        dev->bar4 = bar4;
 
        otx2_update_vf_hwcap(pci_dev, dev);
-       otx2_update_pass_hwcap(pci_dev, dev);
 
        if (otx2_dev_is_vf(dev)) {
                direction = MBOX_DIR_VFPF;
                up_direction = MBOX_DIR_VFPF_UP;
+               intr_offset = RVU_VF_INT;
        }
 
        /* Initialize the local mbox */
-       rc = otx2_mbox_init(&dev->mbox_local, bar4, bar2, direction, 1);
+       rc = otx2_mbox_init(&dev->mbox_local, bar4, bar2, direction, 1,
+                           intr_offset);
        if (rc)
                goto error;
        dev->mbox = &dev->mbox_local;
 
-       rc = otx2_mbox_init(&dev->mbox_up, bar4, bar2, up_direction, 1);
+       rc = otx2_mbox_init(&dev->mbox_up, bar4, bar2, up_direction, 1,
+                           intr_offset);
        if (rc)
                goto error;
 
@@ -807,17 +968,25 @@ otx2_dev_init(struct rte_pci_device *pci_dev, void *otx2_dev)
                }
                /* Init mbox object */
                rc = otx2_mbox_init(&dev->mbox_vfpf, (uintptr_t)hwbase,
-                                   bar2, MBOX_DIR_PFVF, pci_dev->max_vfs);
+                                   bar2, MBOX_DIR_PFVF, pci_dev->max_vfs,
+                                   intr_offset);
                if (rc)
                        goto iounmap;
 
                /* PF -> VF UP messages */
                rc = otx2_mbox_init(&dev->mbox_vfpf_up, (uintptr_t)hwbase,
-                                   bar2, MBOX_DIR_PFVF_UP, pci_dev->max_vfs);
+                                   bar2, MBOX_DIR_PFVF_UP, pci_dev->max_vfs,
+                                   intr_offset);
                if (rc)
                        goto mbox_fini;
        }
 
+       /* Register VF-FLR irq handlers */
+       if (otx2_dev_is_pf(dev)) {
+               rc = vf_flr_register_irqs(pci_dev, dev);
+               if (rc)
+                       goto iounmap;
+       }
        dev->mbox_active = 1;
        return rc;
 
@@ -851,6 +1020,8 @@ otx2_dev_fini(struct rte_pci_device *pci_dev, void *otx2_dev)
 
        mbox_unregister_irq(pci_dev, dev);
 
+       if (otx2_dev_is_pf(dev))
+               vf_flr_unregister_irqs(pci_dev, dev);
        /* Release PF - VF */
        mbox = &dev->mbox_vfpf;
        if (mbox->hwbase && mbox->dev)