Loading...
Note: File does not exist in v3.1.
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}