Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) /* Copyright 2017-2019 NXP */ #include "enetc_pf.h" static void enetc_msg_disable_mr_int(struct enetc_hw *hw) { u32 psiier = enetc_rd(hw, ENETC_PSIIER); /* disable MR int source(s) */ enetc_wr(hw, ENETC_PSIIER, psiier & ~ENETC_PSIIER_MR_MASK); } static void enetc_msg_enable_mr_int(struct enetc_hw *hw) { u32 psiier = enetc_rd(hw, ENETC_PSIIER); enetc_wr(hw, ENETC_PSIIER, psiier | ENETC_PSIIER_MR_MASK); } static irqreturn_t enetc_msg_psi_msix(int irq, void *data) { struct enetc_si *si = (struct enetc_si *)data; struct enetc_pf *pf = enetc_si_priv(si); enetc_msg_disable_mr_int(&si->hw); schedule_work(&pf->msg_task); return IRQ_HANDLED; } static void enetc_msg_task(struct work_struct *work) { struct enetc_pf *pf = container_of(work, struct enetc_pf, msg_task); struct enetc_hw *hw = &pf->si->hw; unsigned long mr_mask; int i; for (;;) { mr_mask = enetc_rd(hw, ENETC_PSIMSGRR) & ENETC_PSIMSGRR_MR_MASK; if (!mr_mask) { /* re-arm MR interrupts, w1c the IDR reg */ enetc_wr(hw, ENETC_PSIIDR, ENETC_PSIIER_MR_MASK); enetc_msg_enable_mr_int(hw); return; } for (i = 0; i < pf->num_vfs; i++) { u32 psimsgrr; u16 msg_code; if (!(ENETC_PSIMSGRR_MR(i) & mr_mask)) continue; enetc_msg_handle_rxmsg(pf, i, &msg_code); psimsgrr = ENETC_SIMSGSR_SET_MC(msg_code); psimsgrr |= ENETC_PSIMSGRR_MR(i); /* w1c */ enetc_wr(hw, ENETC_PSIMSGRR, psimsgrr); } } } /* Init */ static int enetc_msg_alloc_mbx(struct enetc_si *si, int idx) { struct enetc_pf *pf = enetc_si_priv(si); struct device *dev = &si->pdev->dev; struct enetc_hw *hw = &si->hw; struct enetc_msg_swbd *msg; u32 val; msg = &pf->rxmsg[idx]; /* allocate and set receive buffer */ msg->size = ENETC_DEFAULT_MSG_SIZE; msg->vaddr = dma_alloc_coherent(dev, msg->size, &msg->dma, GFP_KERNEL); if (!msg->vaddr) { dev_err(dev, "msg: fail to alloc dma buffer of size: %d\n", msg->size); return -ENOMEM; } /* set multiple of 32 bytes */ val = lower_32_bits(msg->dma); enetc_wr(hw, ENETC_PSIVMSGRCVAR0(idx), val); val = upper_32_bits(msg->dma); enetc_wr(hw, ENETC_PSIVMSGRCVAR1(idx), val); return 0; } static void enetc_msg_free_mbx(struct enetc_si *si, int idx) { struct enetc_pf *pf = enetc_si_priv(si); struct enetc_hw *hw = &si->hw; struct enetc_msg_swbd *msg; msg = &pf->rxmsg[idx]; dma_free_coherent(&si->pdev->dev, msg->size, msg->vaddr, msg->dma); memset(msg, 0, sizeof(*msg)); enetc_wr(hw, ENETC_PSIVMSGRCVAR0(idx), 0); enetc_wr(hw, ENETC_PSIVMSGRCVAR1(idx), 0); } int enetc_msg_psi_init(struct enetc_pf *pf) { struct enetc_si *si = pf->si; int vector, i, err; /* register message passing interrupt handler */ snprintf(pf->msg_int_name, sizeof(pf->msg_int_name), "%s-vfmsg", si->ndev->name); vector = pci_irq_vector(si->pdev, ENETC_SI_INT_IDX); err = request_irq(vector, enetc_msg_psi_msix, 0, pf->msg_int_name, si); if (err) { dev_err(&si->pdev->dev, "PSI messaging: request_irq() failed!\n"); return err; } /* set one IRQ entry for PSI message receive notification (SI int) */ enetc_wr(&si->hw, ENETC_SIMSIVR, ENETC_SI_INT_IDX); /* initialize PSI mailbox */ INIT_WORK(&pf->msg_task, enetc_msg_task); for (i = 0; i < pf->num_vfs; i++) { err = enetc_msg_alloc_mbx(si, i); if (err) goto err_init_mbx; } /* enable MR interrupts */ enetc_msg_enable_mr_int(&si->hw); return 0; err_init_mbx: for (i--; i >= 0; i--) enetc_msg_free_mbx(si, i); free_irq(vector, si); return err; } void enetc_msg_psi_free(struct enetc_pf *pf) { struct enetc_si *si = pf->si; int i; cancel_work_sync(&pf->msg_task); /* disable MR interrupts */ enetc_msg_disable_mr_int(&si->hw); for (i = 0; i < pf->num_vfs; i++) enetc_msg_free_mbx(si, i); /* de-register message passing interrupt handler */ free_irq(pci_irq_vector(si->pdev, ENETC_SI_INT_IDX), si); } |