165 lines · c
1// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)2/* Copyright 2017-2019 NXP */3 4#include "enetc_pf.h"5 6static 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 13static 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 20static 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 31static 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 */64static 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 93static 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 107int 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 140err_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 149void 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