The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/compat/linuxkpi/common/src/linux_interrupt.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2010 Isilon Systems, Inc.
    3  * Copyright (c) 2010 iX Systems, Inc.
    4  * Copyright (c) 2010 Panasas, Inc.
    5  * Copyright (c) 2013-2015 Mellanox Technologies, Ltd.
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice unmodified, this list of conditions, and the following
   13  *    disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  *
   18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   28  *
   29  * $FreeBSD$
   30  */
   31 
   32 #include <linux/device.h>
   33 #include <linux/interrupt.h>
   34 #include <linux/pci.h>
   35 
   36 #include <sys/param.h>
   37 #include <sys/bus.h>
   38 #include <sys/rman.h>
   39 #include <sys/interrupt.h>
   40 
   41 struct irq_ent {
   42         struct list_head        links;
   43         struct device   *dev;
   44         struct resource *res;
   45         void            *arg;
   46         irqreturn_t     (*handler)(int, void *);
   47         irqreturn_t     (*thread_handler)(int, void *);
   48         void            *tag;
   49         unsigned int    irq;
   50 };
   51 
   52 static inline int
   53 lkpi_irq_rid(struct device *dev, unsigned int irq)
   54 {
   55         /* check for MSI- or MSIX- interrupt */
   56         if (irq >= dev->irq_start && irq < dev->irq_end)
   57                 return (irq - dev->irq_start + 1);
   58         else
   59                 return (0);
   60 }
   61 
   62 static inline struct irq_ent *
   63 lkpi_irq_ent(struct device *dev, unsigned int irq)
   64 {
   65         struct irq_ent *irqe;
   66 
   67         list_for_each_entry(irqe, &dev->irqents, links)
   68                 if (irqe->irq == irq)
   69                         return (irqe);
   70 
   71         return (NULL);
   72 }
   73 
   74 static void
   75 lkpi_irq_handler(void *ent)
   76 {
   77         struct irq_ent *irqe;
   78 
   79         if (linux_set_current_flags(curthread, M_NOWAIT))
   80                 return;
   81 
   82         irqe = ent;
   83         if (irqe->handler(irqe->irq, irqe->arg) == IRQ_WAKE_THREAD &&
   84             irqe->thread_handler != NULL) {
   85                 THREAD_SLEEPING_OK();
   86                 irqe->thread_handler(irqe->irq, irqe->arg);
   87                 THREAD_NO_SLEEPING();
   88         }
   89 }
   90 
   91 static inline void
   92 lkpi_irq_release(struct device *dev, struct irq_ent *irqe)
   93 {
   94         if (irqe->tag != NULL)
   95                 bus_teardown_intr(dev->bsddev, irqe->res, irqe->tag);
   96         if (irqe->res != NULL)
   97                 bus_release_resource(dev->bsddev, SYS_RES_IRQ,
   98                     rman_get_rid(irqe->res), irqe->res);
   99         list_del(&irqe->links);
  100 }
  101 
  102 static void
  103 lkpi_devm_irq_release(struct device *dev, void *p)
  104 {
  105         struct irq_ent *irqe;
  106 
  107         if (dev == NULL || p == NULL)
  108                 return;
  109 
  110         irqe = p;
  111         lkpi_irq_release(dev, irqe);
  112 }
  113 
  114 int
  115 lkpi_request_irq(struct device *xdev, unsigned int irq,
  116     irq_handler_t handler, irq_handler_t thread_handler,
  117     unsigned long flags, const char *name, void *arg)
  118 {
  119         struct resource *res;
  120         struct irq_ent *irqe;
  121         struct device *dev;
  122         int error;
  123         int rid;
  124 
  125         dev = linux_pci_find_irq_dev(irq);
  126         if (dev == NULL)
  127                 return -ENXIO;
  128         if (xdev != NULL && xdev != dev)
  129                 return -ENXIO;
  130         rid = lkpi_irq_rid(dev, irq);
  131         res = bus_alloc_resource_any(dev->bsddev, SYS_RES_IRQ, &rid,
  132             flags | RF_ACTIVE);
  133         if (res == NULL)
  134                 return (-ENXIO);
  135         if (xdev != NULL)
  136                 irqe = lkpi_devres_alloc(lkpi_devm_irq_release, sizeof(*irqe),
  137                     GFP_KERNEL | __GFP_ZERO);
  138         else
  139                 irqe = kzalloc(sizeof(*irqe), GFP_KERNEL);
  140         irqe->dev = dev;
  141         irqe->res = res;
  142         irqe->arg = arg;
  143         irqe->handler = handler;
  144         irqe->thread_handler = thread_handler;
  145         irqe->irq = irq;
  146 
  147         error = bus_setup_intr(dev->bsddev, res, INTR_TYPE_NET | INTR_MPSAFE,
  148             NULL, lkpi_irq_handler, irqe, &irqe->tag);
  149         if (error)
  150                 goto errout;
  151         list_add(&irqe->links, &dev->irqents);
  152         if (xdev != NULL)
  153                 devres_add(xdev, irqe);
  154 
  155         return 0;
  156 
  157 errout:
  158         bus_release_resource(dev->bsddev, SYS_RES_IRQ, rid, irqe->res);
  159         if (xdev != NULL)
  160                 devres_free(irqe);
  161         else
  162                 kfree(irqe);
  163         return (-error);
  164 }
  165 
  166 int
  167 lkpi_enable_irq(unsigned int irq)
  168 {
  169         struct irq_ent *irqe;
  170         struct device *dev;
  171 
  172         dev = linux_pci_find_irq_dev(irq);
  173         if (dev == NULL)
  174                 return -EINVAL;
  175         irqe = lkpi_irq_ent(dev, irq);
  176         if (irqe == NULL || irqe->tag != NULL)
  177                 return -EINVAL;
  178         return -bus_setup_intr(dev->bsddev, irqe->res, INTR_TYPE_NET | INTR_MPSAFE,
  179             NULL, lkpi_irq_handler, irqe, &irqe->tag);
  180 }
  181 
  182 void
  183 lkpi_disable_irq(unsigned int irq)
  184 {
  185         struct irq_ent *irqe;
  186         struct device *dev;
  187 
  188         dev = linux_pci_find_irq_dev(irq);
  189         if (dev == NULL)
  190                 return;
  191         irqe = lkpi_irq_ent(dev, irq);
  192         if (irqe == NULL)
  193                 return;
  194         if (irqe->tag != NULL)
  195                 bus_teardown_intr(dev->bsddev, irqe->res, irqe->tag);
  196         irqe->tag = NULL;
  197 }
  198 
  199 int
  200 lkpi_bind_irq_to_cpu(unsigned int irq, int cpu_id)
  201 {
  202         struct irq_ent *irqe;
  203         struct device *dev;
  204 
  205         dev = linux_pci_find_irq_dev(irq);
  206         if (dev == NULL)
  207                 return (-ENOENT);
  208 
  209         irqe = lkpi_irq_ent(dev, irq);
  210         if (irqe == NULL)
  211                 return (-ENOENT);
  212 
  213         return (-bus_bind_intr(dev->bsddev, irqe->res, cpu_id));
  214 }
  215 
  216 void
  217 lkpi_free_irq(unsigned int irq, void *device __unused)
  218 {
  219         struct irq_ent *irqe;
  220         struct device *dev;
  221 
  222         dev = linux_pci_find_irq_dev(irq);
  223         if (dev == NULL)
  224                 return;
  225         irqe = lkpi_irq_ent(dev, irq);
  226         if (irqe == NULL)
  227                 return;
  228         lkpi_irq_release(dev, irqe);
  229         kfree(irqe);
  230 }
  231 
  232 void
  233 lkpi_devm_free_irq(struct device *xdev, unsigned int irq, void *p __unused)
  234 {
  235         struct device *dev;
  236         struct irq_ent *irqe;
  237 
  238         dev = linux_pci_find_irq_dev(irq);
  239         if (dev == NULL)
  240                 return;
  241         if (xdev != dev)
  242                 return;
  243         irqe = lkpi_irq_ent(dev, irq);
  244         if (irqe == NULL)
  245                 return;
  246         lkpi_irq_release(dev, irqe);
  247         lkpi_devres_unlink(dev, irqe);
  248         lkpi_devres_free(irqe);
  249         return;
  250 }

Cache object: b364c4d83c984d257ced532f14a90bab


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.