1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * linux/arch/alpha/kernel/irq.c |
4 | * |
5 | * Copyright (C) 1995 Linus Torvalds |
6 | * |
7 | * This file contains the code used by various IRQ handling routines: |
8 | * asking for different IRQ's should be done through these routines |
9 | * instead of just grabbing them. Thus setups with different IRQ numbers |
10 | * shouldn't result in any weird surprises, and installing new handlers |
11 | * should be easier. |
12 | */ |
13 | |
14 | #include <linux/kernel.h> |
15 | #include <linux/module.h> |
16 | #include <linux/errno.h> |
17 | #include <linux/kernel_stat.h> |
18 | #include <linux/signal.h> |
19 | #include <linux/sched.h> |
20 | #include <linux/ptrace.h> |
21 | #include <linux/interrupt.h> |
22 | #include <linux/random.h> |
23 | #include <linux/irq.h> |
24 | #include <linux/proc_fs.h> |
25 | #include <linux/seq_file.h> |
26 | #include <linux/profile.h> |
27 | #include <linux/bitops.h> |
28 | |
29 | #include <asm/io.h> |
30 | #include <linux/uaccess.h> |
31 | |
32 | volatile unsigned long irq_err_count; |
33 | DEFINE_PER_CPU(unsigned long, irq_pmi_count); |
34 | |
35 | void ack_bad_irq(unsigned int irq) |
36 | { |
37 | irq_err_count++; |
38 | printk(KERN_CRIT "Unexpected IRQ trap at vector %u\n" , irq); |
39 | } |
40 | |
41 | #ifdef CONFIG_SMP |
42 | static char irq_user_affinity[NR_IRQS]; |
43 | |
44 | int irq_select_affinity(unsigned int irq) |
45 | { |
46 | struct irq_data *data = irq_get_irq_data(irq); |
47 | struct irq_chip *chip; |
48 | static int last_cpu; |
49 | int cpu = last_cpu + 1; |
50 | |
51 | if (!data) |
52 | return 1; |
53 | chip = irq_data_get_irq_chip(d: data); |
54 | |
55 | if (!chip->irq_set_affinity || irq_user_affinity[irq]) |
56 | return 1; |
57 | |
58 | while (!cpu_possible(cpu) || |
59 | !cpumask_test_cpu(cpu, cpumask: irq_default_affinity)) |
60 | cpu = (cpu < (NR_CPUS-1) ? cpu + 1 : 0); |
61 | last_cpu = cpu; |
62 | |
63 | irq_data_update_affinity(d: data, cpumask_of(cpu)); |
64 | chip->irq_set_affinity(data, cpumask_of(cpu), false); |
65 | return 0; |
66 | } |
67 | #endif /* CONFIG_SMP */ |
68 | |
69 | int arch_show_interrupts(struct seq_file *p, int prec) |
70 | { |
71 | int j; |
72 | |
73 | #ifdef CONFIG_SMP |
74 | seq_puts(m: p, s: "IPI: " ); |
75 | for_each_online_cpu(j) |
76 | seq_printf(p, "%10lu " , cpu_data[j].ipi_count); |
77 | seq_putc(m: p, c: '\n'); |
78 | #endif |
79 | seq_puts(m: p, s: "PMI: " ); |
80 | for_each_online_cpu(j) |
81 | seq_printf(m: p, fmt: "%10lu " , per_cpu(irq_pmi_count, j)); |
82 | seq_puts(m: p, s: " Performance Monitoring\n" ); |
83 | seq_printf(m: p, fmt: "ERR: %10lu\n" , irq_err_count); |
84 | return 0; |
85 | } |
86 | |
87 | /* |
88 | * handle_irq handles all normal device IRQ's (the special |
89 | * SMP cross-CPU interrupts have their own specific |
90 | * handlers). |
91 | */ |
92 | |
93 | #define MAX_ILLEGAL_IRQS 16 |
94 | |
95 | void |
96 | handle_irq(int irq) |
97 | { |
98 | /* |
99 | * We ack quickly, we don't want the irq controller |
100 | * thinking we're snobs just because some other CPU has |
101 | * disabled global interrupts (we have already done the |
102 | * INT_ACK cycles, it's too late to try to pretend to the |
103 | * controller that we aren't taking the interrupt). |
104 | * |
105 | * 0 return value means that this irq is already being |
106 | * handled by some other CPU. (or is disabled) |
107 | */ |
108 | static unsigned int illegal_count=0; |
109 | struct irq_desc *desc = irq_to_desc(irq); |
110 | |
111 | if (!desc || ((unsigned) irq > ACTUAL_NR_IRQS && |
112 | illegal_count < MAX_ILLEGAL_IRQS)) { |
113 | irq_err_count++; |
114 | illegal_count++; |
115 | printk(KERN_CRIT "device_interrupt: invalid interrupt %d\n" , |
116 | irq); |
117 | return; |
118 | } |
119 | |
120 | irq_enter(); |
121 | generic_handle_irq_desc(desc); |
122 | irq_exit(); |
123 | } |
124 | |