162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) 262306a36Sopenharmony_ci/* Copyright 2017-2019 NXP */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include "enetc_pf.h" 562306a36Sopenharmony_ci 662306a36Sopenharmony_cistatic void enetc_msg_disable_mr_int(struct enetc_hw *hw) 762306a36Sopenharmony_ci{ 862306a36Sopenharmony_ci u32 psiier = enetc_rd(hw, ENETC_PSIIER); 962306a36Sopenharmony_ci /* disable MR int source(s) */ 1062306a36Sopenharmony_ci enetc_wr(hw, ENETC_PSIIER, psiier & ~ENETC_PSIIER_MR_MASK); 1162306a36Sopenharmony_ci} 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_cistatic void enetc_msg_enable_mr_int(struct enetc_hw *hw) 1462306a36Sopenharmony_ci{ 1562306a36Sopenharmony_ci u32 psiier = enetc_rd(hw, ENETC_PSIIER); 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci enetc_wr(hw, ENETC_PSIIER, psiier | ENETC_PSIIER_MR_MASK); 1862306a36Sopenharmony_ci} 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistatic irqreturn_t enetc_msg_psi_msix(int irq, void *data) 2162306a36Sopenharmony_ci{ 2262306a36Sopenharmony_ci struct enetc_si *si = (struct enetc_si *)data; 2362306a36Sopenharmony_ci struct enetc_pf *pf = enetc_si_priv(si); 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci enetc_msg_disable_mr_int(&si->hw); 2662306a36Sopenharmony_ci schedule_work(&pf->msg_task); 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci return IRQ_HANDLED; 2962306a36Sopenharmony_ci} 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic void enetc_msg_task(struct work_struct *work) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci struct enetc_pf *pf = container_of(work, struct enetc_pf, msg_task); 3462306a36Sopenharmony_ci struct enetc_hw *hw = &pf->si->hw; 3562306a36Sopenharmony_ci unsigned long mr_mask; 3662306a36Sopenharmony_ci int i; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci for (;;) { 3962306a36Sopenharmony_ci mr_mask = enetc_rd(hw, ENETC_PSIMSGRR) & ENETC_PSIMSGRR_MR_MASK; 4062306a36Sopenharmony_ci if (!mr_mask) { 4162306a36Sopenharmony_ci /* re-arm MR interrupts, w1c the IDR reg */ 4262306a36Sopenharmony_ci enetc_wr(hw, ENETC_PSIIDR, ENETC_PSIIER_MR_MASK); 4362306a36Sopenharmony_ci enetc_msg_enable_mr_int(hw); 4462306a36Sopenharmony_ci return; 4562306a36Sopenharmony_ci } 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci for (i = 0; i < pf->num_vfs; i++) { 4862306a36Sopenharmony_ci u32 psimsgrr; 4962306a36Sopenharmony_ci u16 msg_code; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci if (!(ENETC_PSIMSGRR_MR(i) & mr_mask)) 5262306a36Sopenharmony_ci continue; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci enetc_msg_handle_rxmsg(pf, i, &msg_code); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci psimsgrr = ENETC_SIMSGSR_SET_MC(msg_code); 5762306a36Sopenharmony_ci psimsgrr |= ENETC_PSIMSGRR_MR(i); /* w1c */ 5862306a36Sopenharmony_ci enetc_wr(hw, ENETC_PSIMSGRR, psimsgrr); 5962306a36Sopenharmony_ci } 6062306a36Sopenharmony_ci } 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci/* Init */ 6462306a36Sopenharmony_cistatic int enetc_msg_alloc_mbx(struct enetc_si *si, int idx) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci struct enetc_pf *pf = enetc_si_priv(si); 6762306a36Sopenharmony_ci struct device *dev = &si->pdev->dev; 6862306a36Sopenharmony_ci struct enetc_hw *hw = &si->hw; 6962306a36Sopenharmony_ci struct enetc_msg_swbd *msg; 7062306a36Sopenharmony_ci u32 val; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci msg = &pf->rxmsg[idx]; 7362306a36Sopenharmony_ci /* allocate and set receive buffer */ 7462306a36Sopenharmony_ci msg->size = ENETC_DEFAULT_MSG_SIZE; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci msg->vaddr = dma_alloc_coherent(dev, msg->size, &msg->dma, 7762306a36Sopenharmony_ci GFP_KERNEL); 7862306a36Sopenharmony_ci if (!msg->vaddr) { 7962306a36Sopenharmony_ci dev_err(dev, "msg: fail to alloc dma buffer of size: %d\n", 8062306a36Sopenharmony_ci msg->size); 8162306a36Sopenharmony_ci return -ENOMEM; 8262306a36Sopenharmony_ci } 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci /* set multiple of 32 bytes */ 8562306a36Sopenharmony_ci val = lower_32_bits(msg->dma); 8662306a36Sopenharmony_ci enetc_wr(hw, ENETC_PSIVMSGRCVAR0(idx), val); 8762306a36Sopenharmony_ci val = upper_32_bits(msg->dma); 8862306a36Sopenharmony_ci enetc_wr(hw, ENETC_PSIVMSGRCVAR1(idx), val); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci return 0; 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic void enetc_msg_free_mbx(struct enetc_si *si, int idx) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci struct enetc_pf *pf = enetc_si_priv(si); 9662306a36Sopenharmony_ci struct enetc_hw *hw = &si->hw; 9762306a36Sopenharmony_ci struct enetc_msg_swbd *msg; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci msg = &pf->rxmsg[idx]; 10062306a36Sopenharmony_ci dma_free_coherent(&si->pdev->dev, msg->size, msg->vaddr, msg->dma); 10162306a36Sopenharmony_ci memset(msg, 0, sizeof(*msg)); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci enetc_wr(hw, ENETC_PSIVMSGRCVAR0(idx), 0); 10462306a36Sopenharmony_ci enetc_wr(hw, ENETC_PSIVMSGRCVAR1(idx), 0); 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ciint enetc_msg_psi_init(struct enetc_pf *pf) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci struct enetc_si *si = pf->si; 11062306a36Sopenharmony_ci int vector, i, err; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci /* register message passing interrupt handler */ 11362306a36Sopenharmony_ci snprintf(pf->msg_int_name, sizeof(pf->msg_int_name), "%s-vfmsg", 11462306a36Sopenharmony_ci si->ndev->name); 11562306a36Sopenharmony_ci vector = pci_irq_vector(si->pdev, ENETC_SI_INT_IDX); 11662306a36Sopenharmony_ci err = request_irq(vector, enetc_msg_psi_msix, 0, pf->msg_int_name, si); 11762306a36Sopenharmony_ci if (err) { 11862306a36Sopenharmony_ci dev_err(&si->pdev->dev, 11962306a36Sopenharmony_ci "PSI messaging: request_irq() failed!\n"); 12062306a36Sopenharmony_ci return err; 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci /* set one IRQ entry for PSI message receive notification (SI int) */ 12462306a36Sopenharmony_ci enetc_wr(&si->hw, ENETC_SIMSIVR, ENETC_SI_INT_IDX); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci /* initialize PSI mailbox */ 12762306a36Sopenharmony_ci INIT_WORK(&pf->msg_task, enetc_msg_task); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci for (i = 0; i < pf->num_vfs; i++) { 13062306a36Sopenharmony_ci err = enetc_msg_alloc_mbx(si, i); 13162306a36Sopenharmony_ci if (err) 13262306a36Sopenharmony_ci goto err_init_mbx; 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci /* enable MR interrupts */ 13662306a36Sopenharmony_ci enetc_msg_enable_mr_int(&si->hw); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci return 0; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cierr_init_mbx: 14162306a36Sopenharmony_ci for (i--; i >= 0; i--) 14262306a36Sopenharmony_ci enetc_msg_free_mbx(si, i); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci free_irq(vector, si); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci return err; 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_civoid enetc_msg_psi_free(struct enetc_pf *pf) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci struct enetc_si *si = pf->si; 15262306a36Sopenharmony_ci int i; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci cancel_work_sync(&pf->msg_task); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci /* disable MR interrupts */ 15762306a36Sopenharmony_ci enetc_msg_disable_mr_int(&si->hw); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci for (i = 0; i < pf->num_vfs; i++) 16062306a36Sopenharmony_ci enetc_msg_free_mbx(si, i); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci /* de-register message passing interrupt handler */ 16362306a36Sopenharmony_ci free_irq(pci_irq_vector(si->pdev, ENETC_SI_INT_IDX), si); 16462306a36Sopenharmony_ci} 165