1219820Sjeff/*- 2219820Sjeff * Copyright (c) 2010 Isilon Systems, Inc. 3219820Sjeff * Copyright (c) 2010 iX Systems, Inc. 4219820Sjeff * Copyright (c) 2010 Panasas, Inc. 5290003Shselasky * Copyright (c) 2013-2015 Mellanox Technologies, Ltd. 6219820Sjeff * All rights reserved. 7219820Sjeff * 8219820Sjeff * Redistribution and use in source and binary forms, with or without 9219820Sjeff * modification, are permitted provided that the following conditions 10219820Sjeff * are met: 11219820Sjeff * 1. Redistributions of source code must retain the above copyright 12219820Sjeff * notice unmodified, this list of conditions, and the following 13219820Sjeff * disclaimer. 14219820Sjeff * 2. Redistributions in binary form must reproduce the above copyright 15219820Sjeff * notice, this list of conditions and the following disclaimer in the 16219820Sjeff * documentation and/or other materials provided with the distribution. 17219820Sjeff * 18219820Sjeff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19219820Sjeff * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20219820Sjeff * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21219820Sjeff * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22219820Sjeff * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23219820Sjeff * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24219820Sjeff * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25219820Sjeff * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26219820Sjeff * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27219820Sjeff * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28289644Shselasky * 29289644Shselasky * $FreeBSD: stable/11/sys/compat/linuxkpi/common/include/linux/interrupt.h 352474 2019-09-18 07:24:33Z hselasky $ 30219820Sjeff */ 31219820Sjeff#ifndef _LINUX_INTERRUPT_H_ 32219820Sjeff#define _LINUX_INTERRUPT_H_ 33219820Sjeff 34219820Sjeff#include <linux/device.h> 35219820Sjeff#include <linux/pci.h> 36329958Shselasky#include <linux/irqreturn.h> 37219820Sjeff 38219820Sjeff#include <sys/bus.h> 39219820Sjeff#include <sys/rman.h> 40219820Sjeff 41219820Sjefftypedef irqreturn_t (*irq_handler_t)(int, void *); 42219820Sjeff 43219820Sjeff#define IRQF_SHARED RF_SHAREABLE 44219820Sjeff 45219820Sjeffstruct irq_ent { 46219820Sjeff struct list_head links; 47219820Sjeff struct device *dev; 48219820Sjeff struct resource *res; 49219820Sjeff void *arg; 50219820Sjeff irqreturn_t (*handler)(int, void *); 51219820Sjeff void *tag; 52310250Shselasky unsigned int irq; 53219820Sjeff}; 54219820Sjeff 55219820Sjeffstatic inline int 56310250Shselaskylinux_irq_rid(struct device *dev, unsigned int irq) 57219820Sjeff{ 58351841Shselasky /* check for MSI- or MSIX- interrupt */ 59351841Shselasky if (irq >= dev->irq_start && irq < dev->irq_end) 60351841Shselasky return (irq - dev->irq_start + 1); 61351841Shselasky else 62219820Sjeff return (0); 63219820Sjeff} 64219820Sjeff 65293419Shselaskyextern void linux_irq_handler(void *); 66219820Sjeff 67219820Sjeffstatic inline struct irq_ent * 68310250Shselaskylinux_irq_ent(struct device *dev, unsigned int irq) 69219820Sjeff{ 70219820Sjeff struct irq_ent *irqe; 71219820Sjeff 72219820Sjeff list_for_each_entry(irqe, &dev->irqents, links) 73219820Sjeff if (irqe->irq == irq) 74219820Sjeff return (irqe); 75219820Sjeff 76219820Sjeff return (NULL); 77219820Sjeff} 78219820Sjeff 79219820Sjeffstatic inline int 80219820Sjeffrequest_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, 81219820Sjeff const char *name, void *arg) 82219820Sjeff{ 83219820Sjeff struct resource *res; 84219820Sjeff struct irq_ent *irqe; 85219820Sjeff struct device *dev; 86219820Sjeff int error; 87219820Sjeff int rid; 88219820Sjeff 89310250Shselasky dev = linux_pci_find_irq_dev(irq); 90219820Sjeff if (dev == NULL) 91219820Sjeff return -ENXIO; 92293419Shselasky rid = linux_irq_rid(dev, irq); 93219820Sjeff res = bus_alloc_resource_any(dev->bsddev, SYS_RES_IRQ, &rid, 94219820Sjeff flags | RF_ACTIVE); 95219820Sjeff if (res == NULL) 96219820Sjeff return (-ENXIO); 97219820Sjeff irqe = kmalloc(sizeof(*irqe), GFP_KERNEL); 98219820Sjeff irqe->dev = dev; 99219820Sjeff irqe->res = res; 100219820Sjeff irqe->arg = arg; 101219820Sjeff irqe->handler = handler; 102219820Sjeff irqe->irq = irq; 103219820Sjeff error = bus_setup_intr(dev->bsddev, res, INTR_TYPE_NET | INTR_MPSAFE, 104293419Shselasky NULL, linux_irq_handler, irqe, &irqe->tag); 105219820Sjeff if (error) { 106219820Sjeff bus_release_resource(dev->bsddev, SYS_RES_IRQ, rid, irqe->res); 107219820Sjeff kfree(irqe); 108219820Sjeff return (-error); 109219820Sjeff } 110219820Sjeff list_add(&irqe->links, &dev->irqents); 111219820Sjeff 112219820Sjeff return 0; 113219820Sjeff} 114219820Sjeff 115290003Shselaskystatic inline int 116329952Shselaskyenable_irq(unsigned int irq) 117329952Shselasky{ 118329952Shselasky struct irq_ent *irqe; 119329952Shselasky struct device *dev; 120329952Shselasky 121329952Shselasky dev = linux_pci_find_irq_dev(irq); 122329952Shselasky if (dev == NULL) 123329952Shselasky return -EINVAL; 124329952Shselasky irqe = linux_irq_ent(dev, irq); 125329957Shselasky if (irqe == NULL || irqe->tag != NULL) 126329952Shselasky return -EINVAL; 127329952Shselasky return -bus_setup_intr(dev->bsddev, irqe->res, INTR_TYPE_NET | INTR_MPSAFE, 128329952Shselasky NULL, linux_irq_handler, irqe, &irqe->tag); 129329952Shselasky} 130329952Shselasky 131329952Shselaskystatic inline void 132329952Shselaskydisable_irq(unsigned int irq) 133329952Shselasky{ 134329952Shselasky struct irq_ent *irqe; 135329952Shselasky struct device *dev; 136329952Shselasky 137329952Shselasky dev = linux_pci_find_irq_dev(irq); 138329952Shselasky if (dev == NULL) 139329952Shselasky return; 140329952Shselasky irqe = linux_irq_ent(dev, irq); 141329952Shselasky if (irqe == NULL) 142329952Shselasky return; 143329957Shselasky if (irqe->tag != NULL) 144329957Shselasky bus_teardown_intr(dev->bsddev, irqe->res, irqe->tag); 145329952Shselasky irqe->tag = NULL; 146329952Shselasky} 147329952Shselasky 148329952Shselaskystatic inline int 149290003Shselaskybind_irq_to_cpu(unsigned int irq, int cpu_id) 150290003Shselasky{ 151290003Shselasky struct irq_ent *irqe; 152290003Shselasky struct device *dev; 153290003Shselasky 154310250Shselasky dev = linux_pci_find_irq_dev(irq); 155290003Shselasky if (dev == NULL) 156290003Shselasky return (-ENOENT); 157290003Shselasky 158293419Shselasky irqe = linux_irq_ent(dev, irq); 159290003Shselasky if (irqe == NULL) 160290003Shselasky return (-ENOENT); 161290003Shselasky 162290003Shselasky return (-bus_bind_intr(dev->bsddev, irqe->res, cpu_id)); 163290003Shselasky} 164290003Shselasky 165219820Sjeffstatic inline void 166219820Sjefffree_irq(unsigned int irq, void *device) 167219820Sjeff{ 168219820Sjeff struct irq_ent *irqe; 169219820Sjeff struct device *dev; 170219820Sjeff int rid; 171219820Sjeff 172310250Shselasky dev = linux_pci_find_irq_dev(irq); 173219820Sjeff if (dev == NULL) 174219820Sjeff return; 175293419Shselasky rid = linux_irq_rid(dev, irq); 176293419Shselasky irqe = linux_irq_ent(dev, irq); 177219820Sjeff if (irqe == NULL) 178219820Sjeff return; 179329957Shselasky if (irqe->tag != NULL) 180329957Shselasky bus_teardown_intr(dev->bsddev, irqe->res, irqe->tag); 181219820Sjeff bus_release_resource(dev->bsddev, SYS_RES_IRQ, rid, irqe->res); 182219820Sjeff list_del(&irqe->links); 183219820Sjeff kfree(irqe); 184219820Sjeff} 185219820Sjeff 186328653Shselasky/* 187328653Shselasky * LinuxKPI tasklet support 188328653Shselasky */ 189328653Shselaskytypedef void tasklet_func_t(unsigned long); 190328653Shselasky 191328653Shselaskystruct tasklet_struct { 192328653Shselasky TAILQ_ENTRY(tasklet_struct) entry; 193328653Shselasky tasklet_func_t *func; 194328653Shselasky unsigned long data; 195328653Shselasky}; 196328653Shselasky 197352474Shselasky#define DECLARE_TASKLET(_name, _func, _data) \ 198352474Shselaskystruct tasklet_struct _name = { .func = (_func), .data = (_data) } 199328653Shselasky 200328653Shselasky#define tasklet_hi_schedule(t) tasklet_schedule(t) 201328653Shselasky 202328653Shselaskyextern void tasklet_schedule(struct tasklet_struct *); 203328653Shselaskyextern void tasklet_kill(struct tasklet_struct *); 204328653Shselaskyextern void tasklet_init(struct tasklet_struct *, tasklet_func_t *, 205328653Shselasky unsigned long data); 206329953Shselaskyextern void tasklet_enable(struct tasklet_struct *); 207329953Shselaskyextern void tasklet_disable(struct tasklet_struct *); 208328653Shselasky 209219820Sjeff#endif /* _LINUX_INTERRUPT_H_ */ 210