162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2020-21 Intel Corporation. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include "iosm_ipc_pcie.h" 762306a36Sopenharmony_ci#include "iosm_ipc_protocol.h" 862306a36Sopenharmony_ci 962306a36Sopenharmony_cistatic void ipc_write_dbell_reg(struct iosm_pcie *ipc_pcie, int irq_n, u32 data) 1062306a36Sopenharmony_ci{ 1162306a36Sopenharmony_ci void __iomem *write_reg; 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci /* Select the first doorbell register, which is only currently needed 1462306a36Sopenharmony_ci * by CP. 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci write_reg = (void __iomem *)((u8 __iomem *)ipc_pcie->ipc_regs + 1762306a36Sopenharmony_ci ipc_pcie->doorbell_write + 1862306a36Sopenharmony_ci (irq_n * ipc_pcie->doorbell_reg_offset)); 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci /* Fire the doorbell irq by writing data on the doorbell write pointer 2162306a36Sopenharmony_ci * register. 2262306a36Sopenharmony_ci */ 2362306a36Sopenharmony_ci iowrite32(data, write_reg); 2462306a36Sopenharmony_ci} 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_civoid ipc_doorbell_fire(struct iosm_pcie *ipc_pcie, int irq_n, u32 data) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci ipc_write_dbell_reg(ipc_pcie, irq_n, data); 2962306a36Sopenharmony_ci} 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/* Threaded Interrupt handler for MSI interrupts */ 3262306a36Sopenharmony_cistatic irqreturn_t ipc_msi_interrupt(int irq, void *dev_id) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci struct iosm_pcie *ipc_pcie = dev_id; 3562306a36Sopenharmony_ci int instance = irq - ipc_pcie->pci->irq; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci /* Shift the MSI irq actions to the IPC tasklet. IRQ_NONE means the 3862306a36Sopenharmony_ci * irq was not from the IPC device or could not be served. 3962306a36Sopenharmony_ci */ 4062306a36Sopenharmony_ci if (instance >= ipc_pcie->nvec) 4162306a36Sopenharmony_ci return IRQ_NONE; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci if (!test_bit(0, &ipc_pcie->suspend)) 4462306a36Sopenharmony_ci ipc_imem_irq_process(ipc_pcie->imem, instance); 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci return IRQ_HANDLED; 4762306a36Sopenharmony_ci} 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_civoid ipc_release_irq(struct iosm_pcie *ipc_pcie) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci struct pci_dev *pdev = ipc_pcie->pci; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci if (pdev->msi_enabled) { 5462306a36Sopenharmony_ci while (--ipc_pcie->nvec >= 0) 5562306a36Sopenharmony_ci free_irq(pdev->irq + ipc_pcie->nvec, ipc_pcie); 5662306a36Sopenharmony_ci } 5762306a36Sopenharmony_ci pci_free_irq_vectors(pdev); 5862306a36Sopenharmony_ci} 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ciint ipc_acquire_irq(struct iosm_pcie *ipc_pcie) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci struct pci_dev *pdev = ipc_pcie->pci; 6362306a36Sopenharmony_ci int i, rc = -EINVAL; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci ipc_pcie->nvec = pci_alloc_irq_vectors(pdev, IPC_MSI_VECTORS, 6662306a36Sopenharmony_ci IPC_MSI_VECTORS, PCI_IRQ_MSI); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci if (ipc_pcie->nvec < 0) { 6962306a36Sopenharmony_ci rc = ipc_pcie->nvec; 7062306a36Sopenharmony_ci goto error; 7162306a36Sopenharmony_ci } 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci if (!pdev->msi_enabled) 7462306a36Sopenharmony_ci goto error; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci for (i = 0; i < ipc_pcie->nvec; ++i) { 7762306a36Sopenharmony_ci rc = request_threaded_irq(pdev->irq + i, NULL, 7862306a36Sopenharmony_ci ipc_msi_interrupt, IRQF_ONESHOT, 7962306a36Sopenharmony_ci KBUILD_MODNAME, ipc_pcie); 8062306a36Sopenharmony_ci if (rc) { 8162306a36Sopenharmony_ci dev_err(ipc_pcie->dev, "unable to grab IRQ, rc=%d", rc); 8262306a36Sopenharmony_ci ipc_pcie->nvec = i; 8362306a36Sopenharmony_ci ipc_release_irq(ipc_pcie); 8462306a36Sopenharmony_ci goto error; 8562306a36Sopenharmony_ci } 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cierror: 8962306a36Sopenharmony_ci return rc; 9062306a36Sopenharmony_ci} 91