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)
{
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
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
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;
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;
}
* 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;
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;
}
/* 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;
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)