1*727fd72fSBen Skeggs /*
2*727fd72fSBen Skeggs  * Copyright 2021 Red Hat Inc.
3*727fd72fSBen Skeggs  *
4*727fd72fSBen Skeggs  * Permission is hereby granted, free of charge, to any person obtaining a
5*727fd72fSBen Skeggs  * copy of this software and associated documentation files (the "Software"),
6*727fd72fSBen Skeggs  * to deal in the Software without restriction, including without limitation
7*727fd72fSBen Skeggs  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*727fd72fSBen Skeggs  * and/or sell copies of the Software, and to permit persons to whom the
9*727fd72fSBen Skeggs  * Software is furnished to do so, subject to the following conditions:
10*727fd72fSBen Skeggs  *
11*727fd72fSBen Skeggs  * The above copyright notice and this permission notice shall be included in
12*727fd72fSBen Skeggs  * all copies or substantial portions of the Software.
13*727fd72fSBen Skeggs  *
14*727fd72fSBen Skeggs  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15*727fd72fSBen Skeggs  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16*727fd72fSBen Skeggs  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17*727fd72fSBen Skeggs  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18*727fd72fSBen Skeggs  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19*727fd72fSBen Skeggs  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20*727fd72fSBen Skeggs  * OTHER DEALINGS IN THE SOFTWARE.
21*727fd72fSBen Skeggs  */
22*727fd72fSBen Skeggs #include <core/intr.h>
23*727fd72fSBen Skeggs 
24*727fd72fSBen Skeggs #include <subdev/pci.h>
25*727fd72fSBen Skeggs #include <subdev/mc.h>
26*727fd72fSBen Skeggs 
27*727fd72fSBen Skeggs static void
28*727fd72fSBen Skeggs nvkm_intr_rearm_locked(struct nvkm_device *device)
29*727fd72fSBen Skeggs {
30*727fd72fSBen Skeggs 	nvkm_mc_intr_rearm(device);
31*727fd72fSBen Skeggs }
32*727fd72fSBen Skeggs 
33*727fd72fSBen Skeggs static void
34*727fd72fSBen Skeggs nvkm_intr_unarm_locked(struct nvkm_device *device)
35*727fd72fSBen Skeggs {
36*727fd72fSBen Skeggs 	nvkm_mc_intr_unarm(device);
37*727fd72fSBen Skeggs }
38*727fd72fSBen Skeggs 
39*727fd72fSBen Skeggs static irqreturn_t
40*727fd72fSBen Skeggs nvkm_intr(int irq, void *arg)
41*727fd72fSBen Skeggs {
42*727fd72fSBen Skeggs 	struct nvkm_device *device = arg;
43*727fd72fSBen Skeggs 	irqreturn_t ret = IRQ_NONE;
44*727fd72fSBen Skeggs 	bool handled;
45*727fd72fSBen Skeggs 
46*727fd72fSBen Skeggs 	spin_lock(&device->intr.lock);
47*727fd72fSBen Skeggs 	if (!device->intr.armed)
48*727fd72fSBen Skeggs 		goto done_unlock;
49*727fd72fSBen Skeggs 
50*727fd72fSBen Skeggs 	nvkm_intr_unarm_locked(device);
51*727fd72fSBen Skeggs 	nvkm_pci_msi_rearm(device);
52*727fd72fSBen Skeggs 
53*727fd72fSBen Skeggs 	nvkm_mc_intr(device, &handled);
54*727fd72fSBen Skeggs 	if (handled)
55*727fd72fSBen Skeggs 		ret = IRQ_HANDLED;
56*727fd72fSBen Skeggs 
57*727fd72fSBen Skeggs 	nvkm_intr_rearm_locked(device);
58*727fd72fSBen Skeggs done_unlock:
59*727fd72fSBen Skeggs 	spin_unlock(&device->intr.lock);
60*727fd72fSBen Skeggs 	return ret;
61*727fd72fSBen Skeggs }
62*727fd72fSBen Skeggs 
63*727fd72fSBen Skeggs void
64*727fd72fSBen Skeggs nvkm_intr_rearm(struct nvkm_device *device)
65*727fd72fSBen Skeggs {
66*727fd72fSBen Skeggs 	spin_lock_irq(&device->intr.lock);
67*727fd72fSBen Skeggs 	nvkm_intr_rearm_locked(device);
68*727fd72fSBen Skeggs 	device->intr.armed = true;
69*727fd72fSBen Skeggs 	spin_unlock_irq(&device->intr.lock);
70*727fd72fSBen Skeggs }
71*727fd72fSBen Skeggs 
72*727fd72fSBen Skeggs void
73*727fd72fSBen Skeggs nvkm_intr_unarm(struct nvkm_device *device)
74*727fd72fSBen Skeggs {
75*727fd72fSBen Skeggs 	spin_lock_irq(&device->intr.lock);
76*727fd72fSBen Skeggs 	nvkm_intr_unarm_locked(device);
77*727fd72fSBen Skeggs 	device->intr.armed = false;
78*727fd72fSBen Skeggs 	spin_unlock_irq(&device->intr.lock);
79*727fd72fSBen Skeggs }
80*727fd72fSBen Skeggs 
81*727fd72fSBen Skeggs int
82*727fd72fSBen Skeggs nvkm_intr_install(struct nvkm_device *device)
83*727fd72fSBen Skeggs {
84*727fd72fSBen Skeggs 	int ret;
85*727fd72fSBen Skeggs 
86*727fd72fSBen Skeggs 	device->intr.irq = device->func->irq(device);
87*727fd72fSBen Skeggs 	if (device->intr.irq < 0)
88*727fd72fSBen Skeggs 		return device->intr.irq;
89*727fd72fSBen Skeggs 
90*727fd72fSBen Skeggs 	ret = request_irq(device->intr.irq, nvkm_intr, IRQF_SHARED, "nvkm", device);
91*727fd72fSBen Skeggs 	if (ret)
92*727fd72fSBen Skeggs 		return ret;
93*727fd72fSBen Skeggs 
94*727fd72fSBen Skeggs 	device->intr.alloc = true;
95*727fd72fSBen Skeggs 	return 0;
96*727fd72fSBen Skeggs }
97*727fd72fSBen Skeggs 
98*727fd72fSBen Skeggs void
99*727fd72fSBen Skeggs nvkm_intr_dtor(struct nvkm_device *device)
100*727fd72fSBen Skeggs {
101*727fd72fSBen Skeggs 	if (device->intr.alloc)
102*727fd72fSBen Skeggs 		free_irq(device->intr.irq, device);
103*727fd72fSBen Skeggs }
104*727fd72fSBen Skeggs 
105*727fd72fSBen Skeggs void
106*727fd72fSBen Skeggs nvkm_intr_ctor(struct nvkm_device *device)
107*727fd72fSBen Skeggs {
108*727fd72fSBen Skeggs 	spin_lock_init(&device->intr.lock);
109*727fd72fSBen Skeggs }
110