void                    *iommu_domain;
        u16                     rbsize; /* Receive buffer size */
 
+#define OTX2_FLAG_INTF_DOWN                    BIT_ULL(2)
+       u64                     flags;
+
        struct otx2_qset        qset;
        struct otx2_hw          hw;
        struct pci_dev          *pdev;
        struct workqueue_struct *mbox_wq;
 
        u16                     pcifunc; /* RVU PF_FUNC */
+       struct cgx_link_user_info linfo;
 
        /* Block address of NIX either BLKADDR_NIX0 or BLKADDR_NIX1 */
        int                     nix_blkaddr;
 void otx2_sqb_flush(struct otx2_nic *pfvf);
 dma_addr_t otx2_alloc_rbuf(struct otx2_nic *pfvf, struct otx2_pool *pool,
                           gfp_t gfp);
+int otx2_rxtx_enable(struct otx2_nic *pfvf, bool enable);
 void otx2_ctx_disable(struct mbox *mbox, int type, bool npa);
 void otx2_cleanup_rx_cqes(struct otx2_nic *pfvf, struct otx2_cq_queue *cq);
 void otx2_cleanup_tx_cqes(struct otx2_nic *pfvf, struct otx2_cq_queue *cq);
 
        otx2_mbox_reset(mbox, 0);
 }
 
+static void otx2_handle_link_event(struct otx2_nic *pf)
+{
+       struct cgx_link_user_info *linfo = &pf->linfo;
+       struct net_device *netdev = pf->netdev;
+
+       pr_info("%s NIC Link is %s %d Mbps %s duplex\n", netdev->name,
+               linfo->link_up ? "UP" : "DOWN", linfo->speed,
+               linfo->full_duplex ? "Full" : "Half");
+       if (linfo->link_up) {
+               netif_carrier_on(netdev);
+               netif_tx_start_all_queues(netdev);
+       } else {
+               netif_tx_stop_all_queues(netdev);
+               netif_carrier_off(netdev);
+       }
+}
+
+int otx2_mbox_up_handler_cgx_link_event(struct otx2_nic *pf,
+                                       struct cgx_link_info_msg *msg,
+                                       struct msg_rsp *rsp)
+{
+       /* Copy the link info sent by AF */
+       pf->linfo = msg->link_info;
+
+       /* interface has not been fully configured yet */
+       if (pf->flags & OTX2_FLAG_INTF_DOWN)
+               return 0;
+
+       otx2_handle_link_event(pf);
+       return 0;
+}
+
 static int otx2_process_mbox_msg_up(struct otx2_nic *pf,
                                    struct mbox_msghdr *req)
 {
        return err;
 }
 
+static int otx2_cgx_config_linkevents(struct otx2_nic *pf, bool enable)
+{
+       struct msg_req *msg;
+       int err;
+
+       otx2_mbox_lock(&pf->mbox);
+       if (enable)
+               msg = otx2_mbox_alloc_msg_cgx_start_linkevents(&pf->mbox);
+       else
+               msg = otx2_mbox_alloc_msg_cgx_stop_linkevents(&pf->mbox);
+
+       if (!msg) {
+               otx2_mbox_unlock(&pf->mbox);
+               return -ENOMEM;
+       }
+
+       err = otx2_sync_mbox_msg(&pf->mbox);
+       otx2_mbox_unlock(&pf->mbox);
+       return err;
+}
+
 static int otx2_set_real_num_queues(struct net_device *netdev,
                                    int tx_queues, int rx_queues)
 {
 
        otx2_set_cints_affinity(pf);
 
+       pf->flags &= ~OTX2_FLAG_INTF_DOWN;
+       /* 'intf_down' may be checked on any cpu */
+       smp_wmb();
+
+       /* we have already received link status notification */
+       if (pf->linfo.link_up && !(pf->pcifunc & RVU_PFVF_FUNC_MASK))
+               otx2_handle_link_event(pf);
+
+       err = otx2_rxtx_enable(pf, true);
+       if (err)
+               goto err_free_cints;
+
        return 0;
 
 err_free_cints:
        netif_carrier_off(netdev);
        netif_tx_stop_all_queues(netdev);
 
+       pf->flags |= OTX2_FLAG_INTF_DOWN;
+       /* 'intf_down' may be checked on any cpu */
+       smp_wmb();
+
+       /* First stop packet Rx/Tx */
+       otx2_rxtx_enable(pf, false);
+
        /* Cleanup CQ NAPI and IRQ */
        vec = pf->hw.nix_msixoff + NIX_LF_CINT_VEC_START;
        for (qidx = 0; qidx < pf->hw.cint_cnt; qidx++) {
        pf->netdev = netdev;
        pf->pdev = pdev;
        pf->dev = dev;
+       pf->flags |= OTX2_FLAG_INTF_DOWN;
 
        hw = &pf->hw;
        hw->pdev = pdev;
                goto err_detach_rsrc;
        }
 
+       /* Enable link notifications */
+       otx2_cgx_config_linkevents(pf, true);
+
        return 0;
 
 err_detach_rsrc:
 
        pf = netdev_priv(netdev);
 
+       /* Disable link notifications */
+       otx2_cgx_config_linkevents(pf, false);
+
        unregister_netdev(netdev);
        otx2_detach_resources(&pf->mbox);
        otx2_disable_mbox_intr(pf);
 
        otx2_write64(pfvf, NIX_LF_CINTX_INT(cq_poll->cint_idx), BIT_ULL(0));
 
        if (workdone < budget && napi_complete_done(napi, workdone)) {
+               /* If interface is going down, don't re-enable IRQ */
+               if (pfvf->flags & OTX2_FLAG_INTF_DOWN)
+                       return workdone;
+
                /* Re-enable interrupts */
                otx2_write64(pfvf, NIX_LF_CINTX_ENA_W1S(cq_poll->cint_idx),
                             BIT_ULL(0));
        otx2_write64(pfvf, NIX_LF_CQ_OP_DOOR,
                     ((u64)cq->cq_idx << 32) | processed_cqe);
 }
+
+int otx2_rxtx_enable(struct otx2_nic *pfvf, bool enable)
+{
+       struct msg_req *msg;
+       int err;
+
+       otx2_mbox_lock(&pfvf->mbox);
+       if (enable)
+               msg = otx2_mbox_alloc_msg_nix_lf_start_rx(&pfvf->mbox);
+       else
+               msg = otx2_mbox_alloc_msg_nix_lf_stop_rx(&pfvf->mbox);
+
+       if (!msg) {
+               otx2_mbox_unlock(&pfvf->mbox);
+               return -ENOMEM;
+       }
+
+       err = otx2_sync_mbox_msg(&pfvf->mbox);
+       otx2_mbox_unlock(&pfvf->mbox);
+       return err;
+}