| |
| |
| |
| #include "enetc_pf.h" |
| |
| static void enetc_msg_disable_mr_int(struct enetc_hw *hw) |
| { |
| <------>u32 psiier = enetc_rd(hw, ENETC_PSIIER); |
| <------> |
| <------>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) { |
| <------><------><------> |
| <------><------><------>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); |
| <------><------><------>enetc_wr(hw, ENETC_PSIMSGRR, psimsgrr); |
| <------><------>} |
| <------>} |
| } |
| |
| |
| 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]; |
| <------> |
| <------>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; |
| <------>} |
| |
| <------> |
| <------>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; |
| |
| <------> |
| <------>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; |
| <------>} |
| |
| <------> |
| <------>enetc_wr(&si->hw, ENETC_SIMSIVR, ENETC_SI_INT_IDX); |
| |
| <------> |
| <------>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; |
| <------>} |
| |
| <------> |
| <------>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); |
| |
| <------> |
| <------>enetc_msg_disable_mr_int(&si->hw); |
| |
| <------>for (i = 0; i < pf->num_vfs; i++) |
| <------><------>enetc_msg_free_mbx(si, i); |
| |
| <------> |
| <------>free_irq(pci_irq_vector(si->pdev, ENETC_SI_INT_IDX), si); |
| } |
| |