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