+ /* Send to VF */
+ otx2_mbox_msg_send(vf_mbox, vf);
+ }
+}
+
+static int
+otx2_mbox_up_handler_cgx_link_event(struct otx2_dev *dev,
+ struct cgx_link_info_msg *msg,
+ struct msg_rsp *rsp)
+{
+ struct cgx_link_user_info *linfo = &msg->link_info;
+
+ otx2_base_dbg("pf:%d/vf:%d NIC Link %s --> 0x%x (%s) from: pf:%d/vf:%d",
+ otx2_get_pf(dev->pf_func), otx2_get_vf(dev->pf_func),
+ linfo->link_up ? "UP" : "DOWN", msg->hdr.id,
+ otx2_mbox_id2name(msg->hdr.id),
+ otx2_get_pf(msg->hdr.pcifunc),
+ otx2_get_vf(msg->hdr.pcifunc));
+
+ /* PF gets link notification from AF */
+ if (otx2_get_pf(msg->hdr.pcifunc) == 0) {
+ if (dev->ops && dev->ops->link_status_update)
+ dev->ops->link_status_update(dev, linfo);
+
+ /* Forward the same message as received from AF to VF */
+ pf_vf_mbox_send_up_msg(dev, msg);
+ } else {
+ /* VF gets link up notification */
+ if (dev->ops && dev->ops->link_status_update)
+ dev->ops->link_status_update(dev, linfo);
+ }
+
+ rsp->hdr.rc = 0;
+ return 0;
+}
+
+static int
+otx2_mbox_up_handler_cgx_ptp_rx_info(struct otx2_dev *dev,
+ struct cgx_ptp_rx_info_msg *msg,
+ struct msg_rsp *rsp)
+{
+ otx2_nix_dbg("pf:%d/vf:%d PTP mode %s --> 0x%x (%s) from: pf:%d/vf:%d",
+ otx2_get_pf(dev->pf_func),
+ otx2_get_vf(dev->pf_func),
+ msg->ptp_en ? "ENABLED" : "DISABLED",
+ msg->hdr.id, otx2_mbox_id2name(msg->hdr.id),
+ otx2_get_pf(msg->hdr.pcifunc),
+ otx2_get_vf(msg->hdr.pcifunc));
+
+ /* PF gets PTP notification from AF */
+ if (otx2_get_pf(msg->hdr.pcifunc) == 0) {
+ if (dev->ops && dev->ops->ptp_info_update)
+ dev->ops->ptp_info_update(dev, msg->ptp_en);
+
+ /* Forward the same message as received from AF to VF */
+ pf_vf_mbox_send_up_msg(dev, msg);
+ } else {
+ /* VF gets PTP notification */
+ if (dev->ops && dev->ops->ptp_info_update)
+ dev->ops->ptp_info_update(dev, msg->ptp_en);
+ }
+
+ rsp->hdr.rc = 0;
+ return 0;
+}
+
+static int
+mbox_process_msgs_up(struct otx2_dev *dev, struct mbox_msghdr *req)
+{
+ /* Check if valid, if not reply with a invalid msg */
+ if (req->sig != OTX2_MBOX_REQ_SIG)
+ return -EIO;
+
+ switch (req->id) {
+#define M(_name, _id, _fn_name, _req_type, _rsp_type) \
+ case _id: { \
+ struct _rsp_type *rsp; \
+ int err; \
+ \
+ rsp = (struct _rsp_type *)otx2_mbox_alloc_msg( \
+ &dev->mbox_up, 0, \
+ sizeof(struct _rsp_type)); \
+ if (!rsp) \
+ return -ENOMEM; \
+ \
+ rsp->hdr.id = _id; \
+ rsp->hdr.sig = OTX2_MBOX_RSP_SIG; \
+ rsp->hdr.pcifunc = dev->pf_func; \
+ rsp->hdr.rc = 0; \
+ \
+ err = otx2_mbox_up_handler_ ## _fn_name( \
+ dev, (struct _req_type *)req, rsp); \
+ return err; \
+ }
+MBOX_UP_CGX_MESSAGES
+#undef M
+
+ default :
+ otx2_reply_invalid_msg(&dev->mbox_up, 0, 0, req->id);
+ }
+
+ return -ENODEV;
+}
+
+static void
+otx2_process_msgs_up(struct otx2_dev *dev, struct otx2_mbox *mbox)
+{
+ struct otx2_mbox_dev *mdev = &mbox->dev[0];
+ struct mbox_hdr *req_hdr;
+ struct mbox_msghdr *msg;
+ int i, err, offset;
+
+ req_hdr = (struct mbox_hdr *)((uintptr_t)mdev->mbase + mbox->rx_start);
+ if (req_hdr->num_msgs == 0)
+ return;
+
+ offset = mbox->rx_start + RTE_ALIGN(sizeof(*req_hdr), MBOX_MSG_ALIGN);
+ for (i = 0; i < req_hdr->num_msgs; i++) {
+ msg = (struct mbox_msghdr *)((uintptr_t)mdev->mbase + offset);
+
+ otx2_base_dbg("Message 0x%x (%s) pf:%d/vf:%d",
+ msg->id, otx2_mbox_id2name(msg->id),
+ otx2_get_pf(msg->pcifunc),
+ otx2_get_vf(msg->pcifunc));
+ err = mbox_process_msgs_up(dev, msg);
+ if (err)
+ otx2_err("Error %d handling 0x%x (%s)",
+ err, msg->id, otx2_mbox_id2name(msg->id));
+ offset = mbox->rx_start + msg->next_msgoff;
+ }
+ /* Send mbox responses */
+ if (mdev->num_msgs) {
+ otx2_base_dbg("Reply num_msgs:%d", mdev->num_msgs);
+ otx2_mbox_msg_send(mbox, 0);
+ }
+}
+
+static void
+otx2_pf_vf_mbox_irq(void *param)
+{
+ struct otx2_dev *dev = param;
+ uint64_t intr;
+
+ intr = otx2_read64(dev->bar2 + RVU_VF_INT);
+ if (intr == 0)
+ 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);
+
+ /* First process all configuration messages */
+ otx2_process_msgs(dev, dev->mbox);
+
+ /* Process Uplink messages */
+ otx2_process_msgs_up(dev, &dev->mbox_up);
+}
+
+static void
+otx2_af_pf_mbox_irq(void *param)
+{
+ struct otx2_dev *dev = param;
+ uint64_t intr;
+
+ intr = otx2_read64(dev->bar2 + RVU_PF_INT);
+ if (intr == 0)
+ 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);
+
+ /* 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_register_pf_irq(struct rte_pci_device *pci_dev, struct otx2_dev *dev)
+{
+ struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+ int i, rc;
+
+ /* HW clear irq */
+ for (i = 0; i < MAX_VFPF_DWORD_BITS; ++i)
+ otx2_write64(~0ull, dev->bar2 +
+ RVU_PF_VFPF_MBOX_INT_ENA_W1CX(i));
+
+ otx2_write64(~0ull, dev->bar2 + RVU_PF_INT_ENA_W1C);
+
+ dev->timer_set = 0;
+
+ /* MBOX interrupt for VF(0...63) <-> PF */
+ rc = otx2_register_irq(intr_handle, otx2_vf_pf_mbox_irq, dev,
+ RVU_PF_INT_VEC_VFPF_MBOX0);
+
+ if (rc) {
+ otx2_err("Fail to register PF(VF0-63) mbox irq");
+ return rc;
+ }
+ /* MBOX interrupt for VF(64...128) <-> PF */
+ rc = otx2_register_irq(intr_handle, otx2_vf_pf_mbox_irq, dev,
+ RVU_PF_INT_VEC_VFPF_MBOX1);
+
+ if (rc) {
+ otx2_err("Fail to register PF(VF64-128) mbox irq");
+ return rc;
+ }
+ /* MBOX interrupt AF <-> PF */
+ rc = otx2_register_irq(intr_handle, otx2_af_pf_mbox_irq,
+ dev, RVU_PF_INT_VEC_AFPF_MBOX);
+ if (rc) {
+ otx2_err("Fail to register AF<->PF mbox irq");
+ return rc;
+ }
+
+ /* HW enable intr */
+ for (i = 0; i < MAX_VFPF_DWORD_BITS; ++i)
+ otx2_write64(~0ull, dev->bar2 +
+ RVU_PF_VFPF_MBOX_INT_ENA_W1SX(i));
+
+ otx2_write64(~0ull, dev->bar2 + RVU_PF_INT);
+ otx2_write64(~0ull, dev->bar2 + RVU_PF_INT_ENA_W1S);
+
+ return rc;
+}
+
+static int
+mbox_register_vf_irq(struct rte_pci_device *pci_dev, struct otx2_dev *dev)
+{
+ struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+ int rc;
+
+ /* Clear irq */
+ otx2_write64(~0ull, dev->bar2 + RVU_VF_INT_ENA_W1C);
+
+ /* MBOX interrupt PF <-> VF */
+ rc = otx2_register_irq(intr_handle, otx2_pf_vf_mbox_irq,
+ dev, RVU_VF_INT_VEC_MBOX);
+ if (rc) {
+ otx2_err("Fail to register PF<->VF mbox irq");
+ return rc;
+ }
+
+ /* HW enable intr */
+ otx2_write64(~0ull, dev->bar2 + RVU_VF_INT);
+ otx2_write64(~0ull, dev->bar2 + RVU_VF_INT_ENA_W1S);
+
+ return rc;
+}
+
+static int
+mbox_register_irq(struct rte_pci_device *pci_dev, struct otx2_dev *dev)
+{
+ if (otx2_dev_is_vf(dev))
+ return mbox_register_vf_irq(pci_dev, dev);
+ else
+ return mbox_register_pf_irq(pci_dev, dev);
+}
+
+static void
+mbox_unregister_pf_irq(struct rte_pci_device *pci_dev, struct otx2_dev *dev)
+{
+ struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+ int i;
+
+ /* HW clear irq */
+ for (i = 0; i < MAX_VFPF_DWORD_BITS; ++i)
+ otx2_write64(~0ull, dev->bar2 +
+ RVU_PF_VFPF_MBOX_INT_ENA_W1CX(i));
+
+ otx2_write64(~0ull, dev->bar2 + RVU_PF_INT_ENA_W1C);
+
+ dev->timer_set = 0;
+
+ rte_eal_alarm_cancel(otx2_vf_pf_mbox_handle_msg, dev);
+
+ /* Unregister the interrupt handler for each vectors */
+ /* MBOX interrupt for VF(0...63) <-> PF */
+ otx2_unregister_irq(intr_handle, otx2_vf_pf_mbox_irq, dev,
+ RVU_PF_INT_VEC_VFPF_MBOX0);
+
+ /* MBOX interrupt for VF(64...128) <-> PF */
+ otx2_unregister_irq(intr_handle, otx2_vf_pf_mbox_irq, dev,
+ RVU_PF_INT_VEC_VFPF_MBOX1);
+
+ /* MBOX interrupt AF <-> PF */
+ otx2_unregister_irq(intr_handle, otx2_af_pf_mbox_irq, dev,
+ RVU_PF_INT_VEC_AFPF_MBOX);
+
+}
+
+static void
+mbox_unregister_vf_irq(struct rte_pci_device *pci_dev, struct otx2_dev *dev)
+{
+ struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+
+ /* Clear irq */
+ otx2_write64(~0ull, dev->bar2 + RVU_VF_INT_ENA_W1C);
+
+ /* Unregister the interrupt handler */
+ otx2_unregister_irq(intr_handle, otx2_pf_vf_mbox_irq, dev,
+ RVU_VF_INT_VEC_MBOX);
+}
+
+static void
+mbox_unregister_irq(struct rte_pci_device *pci_dev, struct otx2_dev *dev)
+{
+ if (otx2_dev_is_vf(dev))
+ mbox_unregister_vf_irq(pci_dev, dev);
+ else
+ 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_pf_vf_flr_irq(void *param)
+{
+ 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;
+}
+
+/**
+ * @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)
+{