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