| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * Copyright (C) 2020-21 Intel Corporation.
- */
- #include "iosm_ipc_pcie.h"
- #include "iosm_ipc_protocol.h"
- static void ipc_write_dbell_reg(struct iosm_pcie *ipc_pcie, int irq_n, u32 data)
- {
- void __iomem *write_reg;
- /* Select the first doorbell register, which is only currently needed
- * by CP.
- */
- write_reg = (void __iomem *)((u8 __iomem *)ipc_pcie->ipc_regs +
- ipc_pcie->doorbell_write +
- (irq_n * ipc_pcie->doorbell_reg_offset));
- /* Fire the doorbell irq by writing data on the doorbell write pointer
- * register.
- */
- iowrite32(data, write_reg);
- }
- void ipc_doorbell_fire(struct iosm_pcie *ipc_pcie, int irq_n, u32 data)
- {
- ipc_write_dbell_reg(ipc_pcie, irq_n, data);
- }
- /* Threaded Interrupt handler for MSI interrupts */
- static irqreturn_t ipc_msi_interrupt(int irq, void *dev_id)
- {
- struct iosm_pcie *ipc_pcie = dev_id;
- int instance = irq - ipc_pcie->pci->irq;
- /* Shift the MSI irq actions to the IPC tasklet. IRQ_NONE means the
- * irq was not from the IPC device or could not be served.
- */
- if (instance >= ipc_pcie->nvec)
- return IRQ_NONE;
- if (!test_bit(0, &ipc_pcie->suspend))
- ipc_imem_irq_process(ipc_pcie->imem, instance);
- return IRQ_HANDLED;
- }
- void ipc_release_irq(struct iosm_pcie *ipc_pcie)
- {
- struct pci_dev *pdev = ipc_pcie->pci;
- if (pdev->msi_enabled) {
- while (--ipc_pcie->nvec >= 0)
- free_irq(pdev->irq + ipc_pcie->nvec, ipc_pcie);
- }
- pci_free_irq_vectors(pdev);
- }
- int ipc_acquire_irq(struct iosm_pcie *ipc_pcie)
- {
- struct pci_dev *pdev = ipc_pcie->pci;
- int i, rc = -EINVAL;
- ipc_pcie->nvec = pci_alloc_irq_vectors(pdev, IPC_MSI_VECTORS,
- IPC_MSI_VECTORS, PCI_IRQ_MSI);
- if (ipc_pcie->nvec < 0) {
- rc = ipc_pcie->nvec;
- goto error;
- }
- if (!pdev->msi_enabled)
- goto error;
- for (i = 0; i < ipc_pcie->nvec; ++i) {
- rc = request_threaded_irq(pdev->irq + i, NULL,
- ipc_msi_interrupt, IRQF_ONESHOT,
- KBUILD_MODNAME, ipc_pcie);
- if (rc) {
- dev_err(ipc_pcie->dev, "unable to grab IRQ, rc=%d", rc);
- ipc_pcie->nvec = i;
- ipc_release_irq(ipc_pcie);
- goto error;
- }
- }
- error:
- return rc;
- }
|