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 9 static 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 26 void 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 */ 32 static 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 49 void 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 60 int 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 88 error: 89 return rc; 90 } 91