linux/kernel/irq/autoprobe.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) 1992, 1998-2004 Linus Torvalds, Ingo Molnar
   4 *
   5 * This file contains the interrupt probing code and driver APIs.
   6 */
   7
   8#include <linux/irq.h>
   9#include <linux/module.h>
  10#include <linux/interrupt.h>
  11#include <linux/delay.h>
  12#include <linux/async.h>
  13
  14#include "internals.h"
  15
  16/*
  17 * Autodetection depends on the fact that any interrupt that
  18 * comes in on to an unassigned handler will get stuck with
  19 * "IRQS_WAITING" cleared and the interrupt disabled.
  20 */
  21static DEFINE_MUTEX(probing_active);
  22
  23/**
  24 *      probe_irq_on    - begin an interrupt autodetect
  25 *
  26 *      Commence probing for an interrupt. The interrupts are scanned
  27 *      and a mask of potential interrupt lines is returned.
  28 *
  29 */
  30unsigned long probe_irq_on(void)
  31{
  32        struct irq_desc *desc;
  33        unsigned long mask = 0;
  34        int i;
  35
  36        /*
  37         * quiesce the kernel, or at least the asynchronous portion
  38         */
  39        async_synchronize_full();
  40        mutex_lock(&probing_active);
  41        /*
  42         * something may have generated an irq long ago and we want to
  43         * flush such a longstanding irq before considering it as spurious.
  44         */
  45        for_each_irq_desc_reverse(i, desc) {
  46                raw_spin_lock_irq(&desc->lock);
  47                if (!desc->action && irq_settings_can_probe(desc)) {
  48                        /*
  49                         * Some chips need to know about probing in
  50                         * progress:
  51                         */
  52                        if (desc->irq_data.chip->irq_set_type)
  53                                desc->irq_data.chip->irq_set_type(&desc->irq_data,
  54                                                         IRQ_TYPE_PROBE);
  55                        irq_activate_and_startup(desc, IRQ_NORESEND);
  56                }
  57                raw_spin_unlock_irq(&desc->lock);
  58        }
  59
  60        /* Wait for longstanding interrupts to trigger. */
  61        msleep(20);
  62
  63        /*
  64         * enable any unassigned irqs
  65         * (we must startup again here because if a longstanding irq
  66         * happened in the previous stage, it may have masked itself)
  67         */
  68        for_each_irq_desc_reverse(i, desc) {
  69                raw_spin_lock_irq(&desc->lock);
  70                if (!desc->action && irq_settings_can_probe(desc)) {
  71                        desc->istate |= IRQS_AUTODETECT | IRQS_WAITING;
  72                        if (irq_activate_and_startup(desc, IRQ_NORESEND))
  73                                desc->istate |= IRQS_PENDING;
  74                }
  75                raw_spin_unlock_irq(&desc->lock);
  76        }
  77
  78        /*
  79         * Wait for spurious interrupts to trigger
  80         */
  81        msleep(100);
  82
  83        /*
  84         * Now filter out any obviously spurious interrupts
  85         */
  86        for_each_irq_desc(i, desc) {
  87                raw_spin_lock_irq(&desc->lock);
  88
  89                if (desc->istate & IRQS_AUTODETECT) {
  90                        /* It triggered already - consider it spurious. */
  91                        if (!(desc->istate & IRQS_WAITING)) {
  92                                desc->istate &= ~IRQS_AUTODETECT;
  93                                irq_shutdown_and_deactivate(desc);
  94                        } else
  95                                if (i < 32)
  96                                        mask |= 1 << i;
  97                }
  98                raw_spin_unlock_irq(&desc->lock);
  99        }
 100
 101        return mask;
 102}
 103EXPORT_SYMBOL(probe_irq_on);
 104
 105/**
 106 *      probe_irq_mask - scan a bitmap of interrupt lines
 107 *      @val:   mask of interrupts to consider
 108 *
 109 *      Scan the interrupt lines and return a bitmap of active
 110 *      autodetect interrupts. The interrupt probe logic state
 111 *      is then returned to its previous value.
 112 *
 113 *      Note: we need to scan all the irq's even though we will
 114 *      only return autodetect irq numbers - just so that we reset
 115 *      them all to a known state.
 116 */
 117unsigned int probe_irq_mask(unsigned long val)
 118{
 119        unsigned int mask = 0;
 120        struct irq_desc *desc;
 121        int i;
 122
 123        for_each_irq_desc(i, desc) {
 124                raw_spin_lock_irq(&desc->lock);
 125                if (desc->istate & IRQS_AUTODETECT) {
 126                        if (i < 16 && !(desc->istate & IRQS_WAITING))
 127                                mask |= 1 << i;
 128
 129                        desc->istate &= ~IRQS_AUTODETECT;
 130                        irq_shutdown_and_deactivate(desc);
 131                }
 132                raw_spin_unlock_irq(&desc->lock);
 133        }
 134        mutex_unlock(&probing_active);
 135
 136        return mask & val;
 137}
 138EXPORT_SYMBOL(probe_irq_mask);
 139
 140/**
 141 *      probe_irq_off   - end an interrupt autodetect
 142 *      @val: mask of potential interrupts (unused)
 143 *
 144 *      Scans the unused interrupt lines and returns the line which
 145 *      appears to have triggered the interrupt. If no interrupt was
 146 *      found then zero is returned. If more than one interrupt is
 147 *      found then minus the first candidate is returned to indicate
 148 *      their is doubt.
 149 *
 150 *      The interrupt probe logic state is returned to its previous
 151 *      value.
 152 *
 153 *      BUGS: When used in a module (which arguably shouldn't happen)
 154 *      nothing prevents two IRQ probe callers from overlapping. The
 155 *      results of this are non-optimal.
 156 */
 157int probe_irq_off(unsigned long val)
 158{
 159        int i, irq_found = 0, nr_of_irqs = 0;
 160        struct irq_desc *desc;
 161
 162        for_each_irq_desc(i, desc) {
 163                raw_spin_lock_irq(&desc->lock);
 164
 165                if (desc->istate & IRQS_AUTODETECT) {
 166                        if (!(desc->istate & IRQS_WAITING)) {
 167                                if (!nr_of_irqs)
 168                                        irq_found = i;
 169                                nr_of_irqs++;
 170                        }
 171                        desc->istate &= ~IRQS_AUTODETECT;
 172                        irq_shutdown_and_deactivate(desc);
 173                }
 174                raw_spin_unlock_irq(&desc->lock);
 175        }
 176        mutex_unlock(&probing_active);
 177
 178        if (nr_of_irqs > 1)
 179                irq_found = -irq_found;
 180
 181        return irq_found;
 182}
 183EXPORT_SYMBOL(probe_irq_off);
 184
 185