iosm_ipc_irq.c (2137B)
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}