Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2020-21 Intel Corporation.
0004  */
0005 
0006 #include "iosm_ipc_pcie.h"
0007 #include "iosm_ipc_protocol.h"
0008 
0009 static void ipc_write_dbell_reg(struct iosm_pcie *ipc_pcie, int irq_n, u32 data)
0010 {
0011     void __iomem *write_reg;
0012 
0013     /* Select the first doorbell register, which is only currently needed
0014      * by CP.
0015      */
0016     write_reg = (void __iomem *)((u8 __iomem *)ipc_pcie->ipc_regs +
0017                      ipc_pcie->doorbell_write +
0018                      (irq_n * ipc_pcie->doorbell_reg_offset));
0019 
0020     /* Fire the doorbell irq by writing data on the doorbell write pointer
0021      * register.
0022      */
0023     iowrite32(data, write_reg);
0024 }
0025 
0026 void ipc_doorbell_fire(struct iosm_pcie *ipc_pcie, int irq_n, u32 data)
0027 {
0028     ipc_write_dbell_reg(ipc_pcie, irq_n, data);
0029 }
0030 
0031 /* Threaded Interrupt handler for MSI interrupts */
0032 static irqreturn_t ipc_msi_interrupt(int irq, void *dev_id)
0033 {
0034     struct iosm_pcie *ipc_pcie = dev_id;
0035     int instance = irq - ipc_pcie->pci->irq;
0036 
0037     /* Shift the MSI irq actions to the IPC tasklet. IRQ_NONE means the
0038      * irq was not from the IPC device or could not be served.
0039      */
0040     if (instance >= ipc_pcie->nvec)
0041         return IRQ_NONE;
0042 
0043     if (!test_bit(0, &ipc_pcie->suspend))
0044         ipc_imem_irq_process(ipc_pcie->imem, instance);
0045 
0046     return IRQ_HANDLED;
0047 }
0048 
0049 void ipc_release_irq(struct iosm_pcie *ipc_pcie)
0050 {
0051     struct pci_dev *pdev = ipc_pcie->pci;
0052 
0053     if (pdev->msi_enabled) {
0054         while (--ipc_pcie->nvec >= 0)
0055             free_irq(pdev->irq + ipc_pcie->nvec, ipc_pcie);
0056     }
0057     pci_free_irq_vectors(pdev);
0058 }
0059 
0060 int ipc_acquire_irq(struct iosm_pcie *ipc_pcie)
0061 {
0062     struct pci_dev *pdev = ipc_pcie->pci;
0063     int i, rc = -EINVAL;
0064 
0065     ipc_pcie->nvec = pci_alloc_irq_vectors(pdev, IPC_MSI_VECTORS,
0066                            IPC_MSI_VECTORS, PCI_IRQ_MSI);
0067 
0068     if (ipc_pcie->nvec < 0) {
0069         rc = ipc_pcie->nvec;
0070         goto error;
0071     }
0072 
0073     if (!pdev->msi_enabled)
0074         goto error;
0075 
0076     for (i = 0; i < ipc_pcie->nvec; ++i) {
0077         rc = request_threaded_irq(pdev->irq + i, NULL,
0078                       ipc_msi_interrupt, IRQF_ONESHOT,
0079                       KBUILD_MODNAME, ipc_pcie);
0080         if (rc) {
0081             dev_err(ipc_pcie->dev, "unable to grab IRQ, rc=%d", rc);
0082             ipc_pcie->nvec = i;
0083             ipc_release_irq(ipc_pcie);
0084             goto error;
0085         }
0086     }
0087 
0088 error:
0089     return rc;
0090 }