linux/drivers/net/ethernet/freescale/enetc/enetc_msg.c
<<
>>
Prefs
   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