GNU Linux-libre 6.8.7-gnu
[releases.git] / drivers / net / wwan / iosm / iosm_ipc_irq.c
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 }