linux/drivers/net/wwan/iosm/iosm_ipc_irq.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) 2020-21 Intel Corporation.
   4 */
   5
   6#include "iosm_ipc_pcie.h"
   7#include "iosm_ipc_protocol.h"
   8
   9static void ipc_write_dbell_reg(struct iosm_pcie *ipc_pcie, int irq_n, u32 data)
  10{
  11        void __iomem *write_reg;
  12
  13        /* Select the first doorbell register, which is only currently needed
  14         * by CP.
  15         */
  16        write_reg = (void __iomem *)((u8 __iomem *)ipc_pcie->ipc_regs +
  17                                     ipc_pcie->doorbell_write +
  18                                     (irq_n * ipc_pcie->doorbell_reg_offset));
  19
  20        /* Fire the doorbell irq by writing data on the doorbell write pointer
  21         * register.
  22         */
  23        iowrite32(data, write_reg);
  24}
  25
  26void ipc_doorbell_fire(struct iosm_pcie *ipc_pcie, int irq_n, u32 data)
  27{
  28        ipc_write_dbell_reg(ipc_pcie, irq_n, data);
  29}
  30
  31/* Threaded Interrupt handler for MSI interrupts */
  32static irqreturn_t ipc_msi_interrupt(int irq, void *dev_id)
  33{
  34        struct iosm_pcie *ipc_pcie = dev_id;
  35        int instance = irq - ipc_pcie->pci->irq;
  36
  37        /* Shift the MSI irq actions to the IPC tasklet. IRQ_NONE means the
  38         * irq was not from the IPC device or could not be served.
  39         */
  40        if (instance >= ipc_pcie->nvec)
  41                return IRQ_NONE;
  42
  43        if (!test_bit(0, &ipc_pcie->suspend))
  44                ipc_imem_irq_process(ipc_pcie->imem, instance);
  45
  46        return IRQ_HANDLED;
  47}
  48
  49void ipc_release_irq(struct iosm_pcie *ipc_pcie)
  50{
  51        struct pci_dev *pdev = ipc_pcie->pci;
  52
  53        if (pdev->msi_enabled) {
  54                while (--ipc_pcie->nvec >= 0)
  55                        free_irq(pdev->irq + ipc_pcie->nvec, ipc_pcie);
  56        }
  57        pci_free_irq_vectors(pdev);
  58}
  59
  60int ipc_acquire_irq(struct iosm_pcie *ipc_pcie)
  61{
  62        struct pci_dev *pdev = ipc_pcie->pci;
  63        int i, rc = -EINVAL;
  64
  65        ipc_pcie->nvec = pci_alloc_irq_vectors(pdev, IPC_MSI_VECTORS,
  66                                               IPC_MSI_VECTORS, PCI_IRQ_MSI);
  67
  68        if (ipc_pcie->nvec < 0) {
  69                rc = ipc_pcie->nvec;
  70                goto error;
  71        }
  72
  73        if (!pdev->msi_enabled)
  74                goto error;
  75
  76        for (i = 0; i < ipc_pcie->nvec; ++i) {
  77                rc = request_threaded_irq(pdev->irq + i, NULL,
  78                                          ipc_msi_interrupt, IRQF_ONESHOT,
  79                                          KBUILD_MODNAME, ipc_pcie);
  80                if (rc) {
  81                        dev_err(ipc_pcie->dev, "unable to grab IRQ, rc=%d", rc);
  82                        ipc_pcie->nvec = i;
  83                        ipc_release_irq(ipc_pcie);
  84                        goto error;
  85                }
  86        }
  87
  88error:
  89        return rc;
  90}
  91