X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fcommon%2Focteontx2%2Fotx2_dev.c;h=0fc799e4ab91d1a7bb3b3495faff3206df78f3a1;hb=5d3e7176ee49efdb81a607a9c13dcfd5c2757de1;hp=486b1b7c8bc718d8c4bb9b41ea84007a51c846d1;hpb=e1d9a02ad8f0fa06ef6ade96d4d14ccd646cea3d;p=dpdk.git diff --git a/drivers/common/octeontx2/otx2_dev.c b/drivers/common/octeontx2/otx2_dev.c index 486b1b7c8b..0fc799e4ab 100644 --- a/drivers/common/octeontx2/otx2_dev.c +++ b/drivers/common/octeontx2/otx2_dev.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -14,6 +15,9 @@ #include "otx2_dev.h" #include "otx2_mbox.h" +#define RVU_MAX_VF 64 /* RVU_PF_VFPF_MBOX_INT(0..1) */ +#define RVU_MAX_INT_RETRY 3 + /* PF/VF message handling timer */ #define VF_PF_MBOX_TIMER_MS (20 * 1000) @@ -47,20 +51,832 @@ 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) +{ + 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_hdr *req_hdr; + struct mbox_msghdr *msg; + struct mbox_msghdr *rsp; + uint64_t offset; + size_t size; + int i; + + /* 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++; + if (timeout >= MBOX_RSP_TIMEOUT) { + otx2_err("Routed messages %d timeout: %dms", + num_msg, MBOX_RSP_TIMEOUT); + break; + } + int_status = otx2_read64(dev->bar2 + RVU_PF_INT); + } while ((int_status & 0x1) != 0x1); + + /* Clear */ + otx2_write64(~0ull, dev->bar2 + RVU_PF_INT); + + /* Enable interrupts */ + otx2_write64(~0ull, dev->bar2 + RVU_PF_INT_ENA_W1S); + + rte_spinlock_lock(&mdev->mbox_lock); + + req_hdr = (struct mbox_hdr *)((uintptr_t)mdev->mbase + mbox->rx_start); + if (req_hdr->num_msgs != num_msg) + otx2_err("Routed messages: %d received: %d", num_msg, + req_hdr->num_msgs); + + /* Get messages from mbox */ + offset = mbox->rx_start + + RTE_ALIGN(sizeof(struct mbox_hdr), MBOX_MSG_ALIGN); + for (i = 0; i < req_hdr->num_msgs; i++) { + msg = (struct mbox_msghdr *)((uintptr_t)mdev->mbase + offset); + size = mbox->rx_start + msg->next_msgoff - offset; + + /* Reserve PF/VF mbox message */ + size = RTE_ALIGN(size, MBOX_MSG_ALIGN); + rsp = otx2_mbox_alloc_msg(&dev->mbox_vfpf, vf, size); + otx2_mbox_rsp_init(msg->id, rsp); + + /* Copy message from AF<->PF mbox to PF<->VF mbox */ + otx2_mbox_memcpy((uint8_t *)rsp + sizeof(struct mbox_msghdr), + (uint8_t *)msg + sizeof(struct mbox_msghdr), + size - sizeof(struct mbox_msghdr)); + + /* Set status and sender pf_func data */ + rsp->rc = msg->rc; + rsp->pcifunc = msg->pcifunc; + + offset = mbox->rx_start + msg->next_msgoff; + } + rte_spinlock_unlock(&mdev->mbox_lock); + + return req_hdr->num_msgs; +} + +static int +vf_pf_process_msgs(struct otx2_dev *dev, uint16_t vf) +{ + int offset, routed = 0; struct otx2_mbox *mbox = &dev->mbox_vfpf; + struct otx2_mbox_dev *mdev = &mbox->dev[vf]; + struct mbox_hdr *req_hdr; + struct mbox_msghdr *msg; + size_t size; + uint16_t i; + + req_hdr = (struct mbox_hdr *)((uintptr_t)mdev->mbase + mbox->rx_start); + if (!req_hdr->num_msgs) + return 0; + + 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); + size = mbox->rx_start + msg->next_msgoff - offset; + + /* RVU_PF_FUNC_S */ + msg->pcifunc = otx2_pfvf_func(dev->pf, vf); + + if (msg->id == MBOX_MSG_READY) { + struct ready_msg_rsp *rsp; + uint16_t max_bits = sizeof(dev->active_vfs[0]) * 8; + + /* Handle READY message in PF */ + dev->active_vfs[vf / max_bits] |= + BIT_ULL(vf % max_bits); + rsp = (struct ready_msg_rsp *) + otx2_mbox_alloc_msg(mbox, vf, sizeof(*rsp)); + otx2_mbox_rsp_init(msg->id, rsp); + + /* PF/VF function ID */ + rsp->hdr.pcifunc = msg->pcifunc; + rsp->hdr.rc = 0; + } else { + struct mbox_msghdr *af_req; + /* Reserve AF/PF mbox message */ + size = RTE_ALIGN(size, MBOX_MSG_ALIGN); + af_req = otx2_mbox_alloc_msg(dev->mbox, 0, size); + otx2_mbox_req_init(msg->id, af_req); + + /* Copy message from VF<->PF mbox to PF<->AF mbox */ + otx2_mbox_memcpy((uint8_t *)af_req + + sizeof(struct mbox_msghdr), + (uint8_t *)msg + sizeof(struct mbox_msghdr), + size - sizeof(struct mbox_msghdr)); + af_req->pcifunc = msg->pcifunc; + routed++; + } + offset = mbox->rx_start + msg->next_msgoff; + } + + if (routed > 0) { + otx2_base_dbg("pf:%d routed %d messages from vf:%d to AF", + dev->pf, routed, vf); + af_pf_wait_msg(dev, vf, routed); + otx2_mbox_reset(dev->mbox, 0); + } + + /* Send mbox responses to VF */ + if (mdev->num_msgs) { + otx2_base_dbg("pf:%d reply %d messages to vf:%d", + dev->pf, mdev->num_msgs, vf); + otx2_mbox_msg_send(mbox, vf); + } + + return i; +} + +static int +vf_pf_process_up_msgs(struct otx2_dev *dev, uint16_t vf) +{ + struct otx2_mbox *mbox = &dev->mbox_vfpf_up; + struct otx2_mbox_dev *mdev = &mbox->dev[vf]; + struct mbox_hdr *req_hdr; + struct mbox_msghdr *msg; + int msgs_acked = 0; + int offset; + uint16_t i; + + req_hdr = (struct mbox_hdr *)((uintptr_t)mdev->mbase + mbox->rx_start); + if (req_hdr->num_msgs == 0) + return 0; + + 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); + + msgs_acked++; + /* RVU_PF_FUNC_S */ + msg->pcifunc = otx2_pfvf_func(dev->pf, vf); + + switch (msg->id) { + case MBOX_MSG_CGX_LINK_EVENT: + otx2_base_dbg("PF: Msg 0x%x (%s) fn:0x%x (pf:%d,vf:%d)", + msg->id, otx2_mbox_id2name(msg->id), + msg->pcifunc, otx2_get_pf(msg->pcifunc), + otx2_get_vf(msg->pcifunc)); + break; + case MBOX_MSG_CGX_PTP_RX_INFO: + otx2_base_dbg("PF: Msg 0x%x (%s) fn:0x%x (pf:%d,vf:%d)", + msg->id, otx2_mbox_id2name(msg->id), + msg->pcifunc, otx2_get_pf(msg->pcifunc), + otx2_get_vf(msg->pcifunc)); + break; + default: + otx2_err("Not handled UP msg 0x%x (%s) func:0x%x", + msg->id, otx2_mbox_id2name(msg->id), + msg->pcifunc); + } + offset = mbox->rx_start + msg->next_msgoff; + } + otx2_mbox_reset(mbox, vf); + mdev->msgs_acked = msgs_acked; + rte_wmb(); + + return i; +} + static void -otx2_update_pass_hwcap(struct rte_pci_device *pci_dev, struct otx2_dev *dev) +otx2_vf_pf_mbox_handle_msg(void *param) { - RTE_SET_USED(pci_dev); + uint16_t vf, max_vf, max_bits; + struct otx2_dev *dev = param; + + max_bits = sizeof(dev->intr.bits[0]) * sizeof(uint64_t); + max_vf = max_bits * MAX_VFPF_DWORD_BITS; - /* Update this logic when we have A1 */ - dev->hwcap |= OTX2_HWCAP_F_A0; + for (vf = 0; vf < max_vf; vf++) { + if (dev->intr.bits[vf/max_bits] & BIT_ULL(vf%max_bits)) { + otx2_base_dbg("Process vf:%d request (pf:%d, vf:%d)", + vf, dev->pf, dev->vf); + vf_pf_process_msgs(dev, vf); + /* UP messages */ + vf_pf_process_up_msgs(dev, vf); + dev->intr.bits[vf/max_bits] &= ~(BIT_ULL(vf%max_bits)); + } + } + dev->timer_set = 0; } static void -otx2_update_vf_hwcap(struct rte_pci_device *pci_dev, struct otx2_dev *dev) +otx2_vf_pf_mbox_irq(void *param) +{ + struct otx2_dev *dev = param; + bool alarm_set = false; + uint64_t intr; + int vfpf; + + for (vfpf = 0; vfpf < MAX_VFPF_DWORD_BITS; ++vfpf) { + intr = otx2_read64(dev->bar2 + RVU_PF_VFPF_MBOX_INTX(vfpf)); + if (!intr) + continue; + + otx2_base_dbg("vfpf: %d intr: 0x%" PRIx64 " (pf:%d, vf:%d)", + vfpf, intr, dev->pf, dev->vf); + + /* Save and clear intr bits */ + dev->intr.bits[vfpf] |= intr; + otx2_write64(intr, dev->bar2 + RVU_PF_VFPF_MBOX_INTX(vfpf)); + alarm_set = true; + } + + if (!dev->timer_set && alarm_set) { + dev->timer_set = 1; + /* Start timer to handle messages */ + rte_eal_alarm_set(VF_PF_MBOX_TIMER_MS, + otx2_vf_pf_mbox_handle_msg, dev); + } +} + +static void +otx2_process_msgs(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 msgs_acked = 0; + int offset; + uint16_t i; + + 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); + + msgs_acked++; + 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)); + + switch (msg->id) { + /* Add message id's that are handled here */ + case MBOX_MSG_READY: + /* Get our identity */ + dev->pf_func = msg->pcifunc; + break; + + default: + if (msg->rc) + otx2_err("Message (%s) response has err=%d", + otx2_mbox_id2name(msg->id), msg->rc); + break; + } + offset = mbox->rx_start + msg->next_msgoff; + } + + otx2_mbox_reset(mbox, 0); + /* Update acked if someone is waiting a message */ + mdev->msgs_acked = msgs_acked; + rte_wmb(); +} + +/* Copies the message received from AF and sends it to VF */ +static void +pf_vf_mbox_send_up_msg(struct otx2_dev *dev, void *rec_msg) +{ + uint16_t max_bits = sizeof(dev->active_vfs[0]) * sizeof(uint64_t); + struct otx2_mbox *vf_mbox = &dev->mbox_vfpf_up; + struct msg_req *msg = rec_msg; + struct mbox_msghdr *vf_msg; + uint16_t vf; + size_t size; + + size = RTE_ALIGN(otx2_mbox_id2size(msg->hdr.id), MBOX_MSG_ALIGN); + /* Send UP message to all VF's */ + for (vf = 0; vf < vf_mbox->ndevs; vf++) { + /* VF active */ + if (!(dev->active_vfs[vf / max_bits] & (BIT_ULL(vf)))) + continue; + + otx2_base_dbg("(%s) size: %zx to VF: %d", + otx2_mbox_id2name(msg->hdr.id), size, vf); + + /* Reserve PF/VF mbox message */ + vf_msg = otx2_mbox_alloc_msg(vf_mbox, vf, size); + if (!vf_msg) { + otx2_err("Failed to alloc VF%d UP message", vf); + continue; + } + otx2_mbox_req_init(msg->hdr.id, vf_msg); + + /* + * Copy message from AF<->PF UP mbox + * to PF<->VF UP mbox + */ + otx2_mbox_memcpy((uint8_t *)vf_msg + + sizeof(struct mbox_msghdr), (uint8_t *)msg + + sizeof(struct mbox_msghdr), size - + sizeof(struct mbox_msghdr)); + + vf_msg->rc = msg->hdr.rc; + /* Set PF to be a sender */ + vf_msg->pcifunc = dev->pf_func; + + /* 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) { - dev->hwcap = 0; + 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) + return; + + 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); + } +} + +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) + return; + + 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); + } +} + +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) +{ switch (pci_dev->id.device_id) { case PCI_DEVID_OCTEONTX2_RVU_PF: break; @@ -69,6 +885,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; } @@ -79,7 +896,7 @@ 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; @@ -103,7 +920,6 @@ 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; @@ -120,10 +936,15 @@ otx2_dev_init(struct rte_pci_device *pci_dev, void *otx2_dev) if (rc) goto error; + /* Register mbox interrupts */ + rc = mbox_register_irq(pci_dev, dev); + if (rc) + goto mbox_fini; + /* Check the readiness of PF/VF */ rc = otx2_send_ready_msg(dev->mbox, &dev->pf_func); if (rc) - goto mbox_fini; + goto mbox_unregister; dev->pf = otx2_get_pf(dev->pf_func); dev->vf = otx2_get_vf(dev->pf_func); @@ -157,11 +978,19 @@ otx2_dev_init(struct rte_pci_device *pci_dev, void *otx2_dev) 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; iounmap: mbox_mem_unmap(hwbase, MBOX_SIZE * pci_dev->max_vfs); +mbox_unregister: + mbox_unregister_irq(pci_dev, dev); mbox_fini: otx2_mbox_fini(dev->mbox); otx2_mbox_fini(&dev->mbox_up); @@ -176,9 +1005,20 @@ error: void otx2_dev_fini(struct rte_pci_device *pci_dev, void *otx2_dev) { + struct rte_intr_handle *intr_handle = &pci_dev->intr_handle; struct otx2_dev *dev = otx2_dev; + struct otx2_idev_cfg *idev; struct otx2_mbox *mbox; + /* Clear references to this pci dev */ + idev = otx2_intra_dev_get_cfg(); + if (idev->npa_lf && idev->npa_lf->pci_dev == pci_dev) + idev->npa_lf = NULL; + + 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) @@ -194,4 +1034,7 @@ otx2_dev_fini(struct rte_pci_device *pci_dev, void *otx2_dev) mbox = &dev->mbox_up; otx2_mbox_fini(mbox); dev->mbox_active = 0; + + /* Disable MSIX vectors */ + otx2_disable_irqs(intr_handle); }