octeontx2: Detect the mbox up or down message via register
[linux-2.6-microblaze.git] / drivers / net / ethernet / marvell / octeontx2 / nic / otx2_pf.c
index e5fe67e..3c8841b 100644 (file)
@@ -292,8 +292,8 @@ static int otx2_pf_flr_init(struct otx2_nic *pf, int num_vfs)
        return 0;
 }
 
-static void otx2_queue_work(struct mbox *mw, struct workqueue_struct *mbox_wq,
-                           int first, int mdevs, u64 intr, int type)
+static void otx2_queue_vf_work(struct mbox *mw, struct workqueue_struct *mbox_wq,
+                              int first, int mdevs, u64 intr)
 {
        struct otx2_mbox_dev *mdev;
        struct otx2_mbox *mbox;
@@ -307,40 +307,26 @@ static void otx2_queue_work(struct mbox *mw, struct workqueue_struct *mbox_wq,
 
                mbox = &mw->mbox;
                mdev = &mbox->dev[i];
-               if (type == TYPE_PFAF)
-                       otx2_sync_mbox_bbuf(mbox, i);
                hdr = mdev->mbase + mbox->rx_start;
                /* The hdr->num_msgs is set to zero immediately in the interrupt
-                * handler to  ensure that it holds a correct value next time
-                * when the interrupt handler is called.
-                * pf->mbox.num_msgs holds the data for use in pfaf_mbox_handler
-                * pf>mbox.up_num_msgs holds the data for use in
-                * pfaf_mbox_up_handler.
+                * handler to ensure that it holds a correct value next time
+                * when the interrupt handler is called. pf->mw[i].num_msgs
+                * holds the data for use in otx2_pfvf_mbox_handler and
+                * pf->mw[i].up_num_msgs holds the data for use in
+                * otx2_pfvf_mbox_up_handler.
                 */
                if (hdr->num_msgs) {
                        mw[i].num_msgs = hdr->num_msgs;
                        hdr->num_msgs = 0;
-                       if (type == TYPE_PFAF)
-                               memset(mbox->hwbase + mbox->rx_start, 0,
-                                      ALIGN(sizeof(struct mbox_hdr),
-                                            sizeof(u64)));
-
                        queue_work(mbox_wq, &mw[i].mbox_wrk);
                }
 
                mbox = &mw->mbox_up;
                mdev = &mbox->dev[i];
-               if (type == TYPE_PFAF)
-                       otx2_sync_mbox_bbuf(mbox, i);
                hdr = mdev->mbase + mbox->rx_start;
                if (hdr->num_msgs) {
                        mw[i].up_num_msgs = hdr->num_msgs;
                        hdr->num_msgs = 0;
-                       if (type == TYPE_PFAF)
-                               memset(mbox->hwbase + mbox->rx_start, 0,
-                                      ALIGN(sizeof(struct mbox_hdr),
-                                            sizeof(u64)));
-
                        queue_work(mbox_wq, &mw[i].mbox_up_wrk);
                }
        }
@@ -356,8 +342,10 @@ static void otx2_forward_msg_pfvf(struct otx2_mbox_dev *mdev,
        /* Msgs are already copied, trigger VF's mbox irq */
        smp_wmb();
 
+       otx2_mbox_wait_for_zero(pfvf_mbox, devid);
+
        offset = pfvf_mbox->trigger | (devid << pfvf_mbox->tr_shift);
-       writeq(1, (void __iomem *)pfvf_mbox->reg_base + offset);
+       writeq(MBOX_DOWN_MSG, (void __iomem *)pfvf_mbox->reg_base + offset);
 
        /* Restore VF's mbox bounce buffer region address */
        src_mdev->mbase = bbuf_base;
@@ -547,7 +535,7 @@ static void otx2_pfvf_mbox_up_handler(struct work_struct *work)
 end:
                offset = mbox->rx_start + msg->next_msgoff;
                if (mdev->msgs_acked == (vf_mbox->up_num_msgs - 1))
-                       __otx2_mbox_reset(mbox, 0);
+                       __otx2_mbox_reset(mbox, vf_idx);
                mdev->msgs_acked++;
        }
 }
@@ -564,8 +552,7 @@ static irqreturn_t otx2_pfvf_mbox_intr_handler(int irq, void *pf_irq)
        if (vfs > 64) {
                intr = otx2_read64(pf, RVU_PF_VFPF_MBOX_INTX(1));
                otx2_write64(pf, RVU_PF_VFPF_MBOX_INTX(1), intr);
-               otx2_queue_work(mbox, pf->mbox_pfvf_wq, 64, vfs, intr,
-                               TYPE_PFVF);
+               otx2_queue_vf_work(mbox, pf->mbox_pfvf_wq, 64, vfs, intr);
                if (intr)
                        trace_otx2_msg_interrupt(mbox->mbox.pdev, "VF(s) to PF", intr);
                vfs = 64;
@@ -574,7 +561,7 @@ static irqreturn_t otx2_pfvf_mbox_intr_handler(int irq, void *pf_irq)
        intr = otx2_read64(pf, RVU_PF_VFPF_MBOX_INTX(0));
        otx2_write64(pf, RVU_PF_VFPF_MBOX_INTX(0), intr);
 
-       otx2_queue_work(mbox, pf->mbox_pfvf_wq, 0, vfs, intr, TYPE_PFVF);
+       otx2_queue_vf_work(mbox, pf->mbox_pfvf_wq, 0, vfs, intr);
 
        if (intr)
                trace_otx2_msg_interrupt(mbox->mbox.pdev, "VF(s) to PF", intr);
@@ -821,20 +808,22 @@ static void otx2_pfaf_mbox_handler(struct work_struct *work)
        struct mbox *af_mbox;
        struct otx2_nic *pf;
        int offset, id;
+       u16 num_msgs;
 
        af_mbox = container_of(work, struct mbox, mbox_wrk);
        mbox = &af_mbox->mbox;
        mdev = &mbox->dev[0];
        rsp_hdr = (struct mbox_hdr *)(mdev->mbase + mbox->rx_start);
+       num_msgs = rsp_hdr->num_msgs;
 
        offset = mbox->rx_start + ALIGN(sizeof(*rsp_hdr), MBOX_MSG_ALIGN);
        pf = af_mbox->pfvf;
 
-       for (id = 0; id < af_mbox->num_msgs; id++) {
+       for (id = 0; id < num_msgs; id++) {
                msg = (struct mbox_msghdr *)(mdev->mbase + offset);
                otx2_process_pfaf_mbox_msg(pf, msg);
                offset = mbox->rx_start + msg->next_msgoff;
-               if (mdev->msgs_acked == (af_mbox->num_msgs - 1))
+               if (mdev->msgs_acked == (num_msgs - 1))
                        __otx2_mbox_reset(mbox, 0);
                mdev->msgs_acked++;
        }
@@ -945,12 +934,14 @@ static void otx2_pfaf_mbox_up_handler(struct work_struct *work)
        int offset, id, devid = 0;
        struct mbox_hdr *rsp_hdr;
        struct mbox_msghdr *msg;
+       u16 num_msgs;
 
        rsp_hdr = (struct mbox_hdr *)(mdev->mbase + mbox->rx_start);
+       num_msgs = rsp_hdr->num_msgs;
 
        offset = mbox->rx_start + ALIGN(sizeof(*rsp_hdr), MBOX_MSG_ALIGN);
 
-       for (id = 0; id < af_mbox->up_num_msgs; id++) {
+       for (id = 0; id < num_msgs; id++) {
                msg = (struct mbox_msghdr *)(mdev->mbase + offset);
 
                devid = msg->pcifunc & RVU_PFVF_FUNC_MASK;
@@ -959,10 +950,11 @@ static void otx2_pfaf_mbox_up_handler(struct work_struct *work)
                        otx2_process_mbox_msg_up(pf, msg);
                offset = mbox->rx_start + msg->next_msgoff;
        }
-       if (devid) {
+       /* Forward to VF iff VFs are really present */
+       if (devid && pci_num_vf(pf->pdev)) {
                otx2_forward_vf_mbox_msgs(pf, &pf->mbox.mbox_up,
                                          MBOX_DIR_PFVF_UP, devid - 1,
-                                         af_mbox->up_num_msgs);
+                                         num_msgs);
                return;
        }
 
@@ -972,16 +964,49 @@ static void otx2_pfaf_mbox_up_handler(struct work_struct *work)
 static irqreturn_t otx2_pfaf_mbox_intr_handler(int irq, void *pf_irq)
 {
        struct otx2_nic *pf = (struct otx2_nic *)pf_irq;
-       struct mbox *mbox;
+       struct mbox *mw = &pf->mbox;
+       struct otx2_mbox_dev *mdev;
+       struct otx2_mbox *mbox;
+       struct mbox_hdr *hdr;
+       u64 mbox_data;
 
        /* Clear the IRQ */
        otx2_write64(pf, RVU_PF_INT, BIT_ULL(0));
 
-       mbox = &pf->mbox;
 
-       trace_otx2_msg_interrupt(mbox->mbox.pdev, "AF to PF", BIT_ULL(0));
+       mbox_data = otx2_read64(pf, RVU_PF_PFAF_MBOX0);
+
+       if (mbox_data & MBOX_UP_MSG) {
+               mbox_data &= ~MBOX_UP_MSG;
+               otx2_write64(pf, RVU_PF_PFAF_MBOX0, mbox_data);
+
+               mbox = &mw->mbox_up;
+               mdev = &mbox->dev[0];
+               otx2_sync_mbox_bbuf(mbox, 0);
+
+               hdr = (struct mbox_hdr *)(mdev->mbase + mbox->rx_start);
+               if (hdr->num_msgs)
+                       queue_work(pf->mbox_wq, &mw->mbox_up_wrk);
+
+               trace_otx2_msg_interrupt(pf->pdev, "UP message from AF to PF",
+                                        BIT_ULL(0));
+       }
+
+       if (mbox_data & MBOX_DOWN_MSG) {
+               mbox_data &= ~MBOX_DOWN_MSG;
+               otx2_write64(pf, RVU_PF_PFAF_MBOX0, mbox_data);
+
+               mbox = &mw->mbox;
+               mdev = &mbox->dev[0];
+               otx2_sync_mbox_bbuf(mbox, 0);
+
+               hdr = (struct mbox_hdr *)(mdev->mbase + mbox->rx_start);
+               if (hdr->num_msgs)
+                       queue_work(pf->mbox_wq, &mw->mbox_wrk);
 
-       otx2_queue_work(mbox, pf->mbox_wq, 0, 1, 1, TYPE_PFAF);
+               trace_otx2_msg_interrupt(pf->pdev, "DOWN reply from AF to PF",
+                                        BIT_ULL(0));
+       }
 
        return IRQ_HANDLED;
 }
@@ -3087,6 +3112,7 @@ static void otx2_vf_link_event_task(struct work_struct *work)
        struct otx2_vf_config *config;
        struct cgx_link_info_msg *req;
        struct mbox_msghdr *msghdr;
+       struct delayed_work *dwork;
        struct otx2_nic *pf;
        int vf_idx;
 
@@ -3095,10 +3121,21 @@ static void otx2_vf_link_event_task(struct work_struct *work)
        vf_idx = config - config->pf->vf_configs;
        pf = config->pf;
 
+       mutex_lock(&pf->mbox.lock);
+
+       dwork = &config->link_event_work;
+
+       if (!otx2_mbox_wait_for_zero(&pf->mbox_pfvf[0].mbox_up, vf_idx)) {
+               schedule_delayed_work(dwork, msecs_to_jiffies(100));
+               mutex_unlock(&pf->mbox.lock);
+               return;
+       }
+
        msghdr = otx2_mbox_alloc_msg_rsp(&pf->mbox_pfvf[0].mbox_up, vf_idx,
                                         sizeof(*req), sizeof(struct msg_rsp));
        if (!msghdr) {
                dev_err(pf->dev, "Failed to create VF%d link event\n", vf_idx);
+               mutex_unlock(&pf->mbox.lock);
                return;
        }
 
@@ -3107,7 +3144,11 @@ static void otx2_vf_link_event_task(struct work_struct *work)
        req->hdr.sig = OTX2_MBOX_REQ_SIG;
        memcpy(&req->link_info, &pf->linfo, sizeof(req->link_info));
 
-       otx2_sync_mbox_up_msg(&pf->mbox_pfvf[0], vf_idx);
+       otx2_mbox_wait_for_zero(&pf->mbox_pfvf[0].mbox_up, vf_idx);
+
+       otx2_mbox_msg_send_up(&pf->mbox_pfvf[0].mbox_up, vf_idx);
+
+       mutex_unlock(&pf->mbox.lock);
 }
 
 static int otx2_sriov_enable(struct pci_dev *pdev, int numvfs)