irq.c 12.1 KB
Newer Older
1 2 3 4 5 6
/*
 * Common interrupt code for 32 and 64 bit
 */
#include <linux/cpu.h>
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
7
#include <linux/of.h>
8
#include <linux/seq_file.h>
9
#include <linux/smp.h>
J
Jeremy Fitzhardinge 已提交
10
#include <linux/ftrace.h>
11
#include <linux/delay.h>
12
#include <linux/export.h>
13

I
Ingo Molnar 已提交
14
#include <asm/apic.h>
15
#include <asm/io_apic.h>
16
#include <asm/irq.h>
J
Jeremy Fitzhardinge 已提交
17
#include <asm/idle.h>
18
#include <asm/mce.h>
19
#include <asm/hw_irq.h>
20 21

#define CREATE_TRACE_POINTS
22
#include <asm/trace/irq_vectors.h>
23 24 25

atomic_t irq_err_count;

26
/* Function pointer for generic interrupt vector handling */
27
void (*x86_platform_ipi_callback)(void) = NULL;
28

T
Thomas Gleixner 已提交
29 30 31 32 33 34
/*
 * 'what should we do if we get a hw irq event on an illegal vector'.
 * each architecture has to answer this themselves.
 */
void ack_bad_irq(unsigned int irq)
{
C
Cyrill Gorcunov 已提交
35 36
	if (printk_ratelimit())
		pr_err("unexpected IRQ trap at vector %02x\n", irq);
T
Thomas Gleixner 已提交
37 38 39 40 41 42 43 44 45 46

	/*
	 * Currently unexpected vectors happen only on SMP and APIC.
	 * We _must_ ack these because every local APIC has only N
	 * irq slots per priority level, and a 'hanging, unacked' IRQ
	 * holds up an irq slot - in excessive cases (when multiple
	 * unexpected vectors occur) that might lock up the APIC
	 * completely.
	 * But only ack when the APIC is enabled -AK
	 */
47
	ack_APIC_irq();
T
Thomas Gleixner 已提交
48 49
}

50
#define irq_stats(x)		(&per_cpu(irq_stat, x))
51
/*
52
 * /proc/interrupts printing for arch specific interrupts
53
 */
54
int arch_show_interrupts(struct seq_file *p, int prec)
55 56 57
{
	int j;

58
	seq_printf(p, "%*s: ", prec, "NMI");
59 60 61 62
	for_each_online_cpu(j)
		seq_printf(p, "%10u ", irq_stats(j)->__nmi_count);
	seq_printf(p, "  Non-maskable interrupts\n");
#ifdef CONFIG_X86_LOCAL_APIC
63
	seq_printf(p, "%*s: ", prec, "LOC");
64 65 66
	for_each_online_cpu(j)
		seq_printf(p, "%10u ", irq_stats(j)->apic_timer_irqs);
	seq_printf(p, "  Local timer interrupts\n");
67 68 69 70 71

	seq_printf(p, "%*s: ", prec, "SPU");
	for_each_online_cpu(j)
		seq_printf(p, "%10u ", irq_stats(j)->irq_spurious_count);
	seq_printf(p, "  Spurious interrupts\n");
72
	seq_printf(p, "%*s: ", prec, "PMI");
I
Ingo Molnar 已提交
73 74
	for_each_online_cpu(j)
		seq_printf(p, "%10u ", irq_stats(j)->apic_perf_irqs);
75
	seq_printf(p, "  Performance monitoring interrupts\n");
76
	seq_printf(p, "%*s: ", prec, "IWI");
77
	for_each_online_cpu(j)
78 79
		seq_printf(p, "%10u ", irq_stats(j)->apic_irq_work_irqs);
	seq_printf(p, "  IRQ work interrupts\n");
80 81
	seq_printf(p, "%*s: ", prec, "RTR");
	for_each_online_cpu(j)
82
		seq_printf(p, "%10u ", irq_stats(j)->icr_read_retry_count);
83
	seq_printf(p, "  APIC ICR read retries\n");
84
#endif
85
	if (x86_platform_ipi_callback) {
86
		seq_printf(p, "%*s: ", prec, "PLT");
87
		for_each_online_cpu(j)
88
			seq_printf(p, "%10u ", irq_stats(j)->x86_platform_ipis);
89 90
		seq_printf(p, "  Platform interrupts\n");
	}
91
#ifdef CONFIG_SMP
92
	seq_printf(p, "%*s: ", prec, "RES");
93 94 95
	for_each_online_cpu(j)
		seq_printf(p, "%10u ", irq_stats(j)->irq_resched_count);
	seq_printf(p, "  Rescheduling interrupts\n");
96
	seq_printf(p, "%*s: ", prec, "CAL");
97
	for_each_online_cpu(j)
98 99
		seq_printf(p, "%10u ", irq_stats(j)->irq_call_count -
					irq_stats(j)->irq_tlb_count);
100
	seq_printf(p, "  Function call interrupts\n");
101
	seq_printf(p, "%*s: ", prec, "TLB");
102 103 104 105
	for_each_online_cpu(j)
		seq_printf(p, "%10u ", irq_stats(j)->irq_tlb_count);
	seq_printf(p, "  TLB shootdowns\n");
#endif
106
#ifdef CONFIG_X86_THERMAL_VECTOR
107
	seq_printf(p, "%*s: ", prec, "TRM");
108 109 110
	for_each_online_cpu(j)
		seq_printf(p, "%10u ", irq_stats(j)->irq_thermal_count);
	seq_printf(p, "  Thermal event interrupts\n");
111 112
#endif
#ifdef CONFIG_X86_MCE_THRESHOLD
113
	seq_printf(p, "%*s: ", prec, "THR");
114 115 116
	for_each_online_cpu(j)
		seq_printf(p, "%10u ", irq_stats(j)->irq_threshold_count);
	seq_printf(p, "  Threshold APIC interrupts\n");
117
#endif
118
#ifdef CONFIG_X86_MCE
119 120 121 122
	seq_printf(p, "%*s: ", prec, "MCE");
	for_each_online_cpu(j)
		seq_printf(p, "%10u ", per_cpu(mce_exception_count, j));
	seq_printf(p, "  Machine check exceptions\n");
123 124 125 126
	seq_printf(p, "%*s: ", prec, "MCP");
	for_each_online_cpu(j)
		seq_printf(p, "%10u ", per_cpu(mce_poll_count, j));
	seq_printf(p, "  Machine check polls\n");
127
#endif
128
#if IS_ENABLED(CONFIG_HYPERV) || defined(CONFIG_XEN)
129 130 131 132 133
	seq_printf(p, "%*s: ", prec, "THR");
	for_each_online_cpu(j)
		seq_printf(p, "%10u ", irq_stats(j)->irq_hv_callback_count);
	seq_printf(p, "  Hypervisor callback interrupts\n");
#endif
134
	seq_printf(p, "%*s: %10u\n", prec, "ERR", atomic_read(&irq_err_count));
135
#if defined(CONFIG_X86_IO_APIC)
136
	seq_printf(p, "%*s: %10u\n", prec, "MIS", atomic_read(&irq_mis_count));
137 138 139 140 141 142 143 144 145 146 147 148 149
#endif
	return 0;
}

/*
 * /proc/stat helpers
 */
u64 arch_irq_stat_cpu(unsigned int cpu)
{
	u64 sum = irq_stats(cpu)->__nmi_count;

#ifdef CONFIG_X86_LOCAL_APIC
	sum += irq_stats(cpu)->apic_timer_irqs;
150
	sum += irq_stats(cpu)->irq_spurious_count;
I
Ingo Molnar 已提交
151
	sum += irq_stats(cpu)->apic_perf_irqs;
152
	sum += irq_stats(cpu)->apic_irq_work_irqs;
153
	sum += irq_stats(cpu)->icr_read_retry_count;
154
#endif
155 156
	if (x86_platform_ipi_callback)
		sum += irq_stats(cpu)->x86_platform_ipis;
157 158 159 160
#ifdef CONFIG_SMP
	sum += irq_stats(cpu)->irq_resched_count;
	sum += irq_stats(cpu)->irq_call_count;
#endif
161
#ifdef CONFIG_X86_THERMAL_VECTOR
162
	sum += irq_stats(cpu)->irq_thermal_count;
163 164
#endif
#ifdef CONFIG_X86_MCE_THRESHOLD
165
	sum += irq_stats(cpu)->irq_threshold_count;
H
Hidetoshi Seto 已提交
166
#endif
167
#ifdef CONFIG_X86_MCE
H
Hidetoshi Seto 已提交
168 169
	sum += per_cpu(mce_exception_count, cpu);
	sum += per_cpu(mce_poll_count, cpu);
170 171 172 173 174 175 176 177 178
#endif
	return sum;
}

u64 arch_irq_stat(void)
{
	u64 sum = atomic_read(&irq_err_count);
	return sum;
}
179

J
Jeremy Fitzhardinge 已提交
180 181 182 183 184 185

/*
 * do_IRQ handles all normal device IRQ's (the special
 * SMP cross-CPU interrupts have their own specific
 * handlers).
 */
186
__visible unsigned int __irq_entry do_IRQ(struct pt_regs *regs)
J
Jeremy Fitzhardinge 已提交
187 188 189 190 191 192 193 194
{
	struct pt_regs *old_regs = set_irq_regs(regs);

	/* high bit used in ret_from_ code  */
	unsigned vector = ~regs->orig_ax;
	unsigned irq;

	irq_enter();
195
	exit_idle();
J
Jeremy Fitzhardinge 已提交
196

T
Tejun Heo 已提交
197
	irq = __this_cpu_read(vector_irq[vector]);
J
Jeremy Fitzhardinge 已提交
198 199

	if (!handle_irq(irq, regs)) {
200
		ack_APIC_irq();
J
Jeremy Fitzhardinge 已提交
201

202 203 204 205 206 207 208
		if (irq != VECTOR_RETRIGGERED) {
			pr_emerg_ratelimited("%s: %d.%d No irq handler for vector (irq %d)\n",
					     __func__, smp_processor_id(),
					     vector, irq);
		} else {
			__this_cpu_write(vector_irq[vector], VECTOR_UNDEFINED);
		}
J
Jeremy Fitzhardinge 已提交
209 210 211 212 213 214 215 216
	}

	irq_exit();

	set_irq_regs(old_regs);
	return 1;
}

217
/*
218
 * Handler for X86_PLATFORM_IPI_VECTOR.
219
 */
220
void __smp_x86_platform_ipi(void)
221
{
222
	inc_irq_stat(x86_platform_ipis);
223

224 225
	if (x86_platform_ipi_callback)
		x86_platform_ipi_callback();
226
}
227

228
__visible void smp_x86_platform_ipi(struct pt_regs *regs)
229 230
{
	struct pt_regs *old_regs = set_irq_regs(regs);
231

232 233 234
	entering_ack_irq();
	__smp_x86_platform_ipi();
	exiting_irq();
235 236 237
	set_irq_regs(old_regs);
}

238 239 240 241
#ifdef CONFIG_HAVE_KVM
/*
 * Handler for POSTED_INTERRUPT_VECTOR.
 */
242
__visible void smp_kvm_posted_intr_ipi(struct pt_regs *regs)
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
{
	struct pt_regs *old_regs = set_irq_regs(regs);

	ack_APIC_irq();

	irq_enter();

	exit_idle();

	inc_irq_stat(kvm_posted_intr_ipis);

	irq_exit();

	set_irq_regs(old_regs);
}
#endif

260
__visible void smp_trace_x86_platform_ipi(struct pt_regs *regs)
261 262 263 264 265 266 267 268 269 270 271
{
	struct pt_regs *old_regs = set_irq_regs(regs);

	entering_ack_irq();
	trace_x86_platform_ipi_entry(X86_PLATFORM_IPI_VECTOR);
	__smp_x86_platform_ipi();
	trace_x86_platform_ipi_exit(X86_PLATFORM_IPI_VECTOR);
	exiting_irq();
	set_irq_regs(old_regs);
}

272
EXPORT_SYMBOL_GPL(vector_used_by_percpu_irq);
273 274

#ifdef CONFIG_HOTPLUG_CPU
275 276 277 278 279 280 281 282

/* These two declarations are only used in check_irq_vectors_for_cpu_disable()
 * below, which is protected by stop_machine().  Putting them on the stack
 * results in a stack frame overflow.  Dynamically allocating could result in a
 * failure so declare these two cpumasks as global.
 */
static struct cpumask affinity_new, online_new;

283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
/*
 * This cpu is going to be removed and its vectors migrated to the remaining
 * online cpus.  Check to see if there are enough vectors in the remaining cpus.
 * This function is protected by stop_machine().
 */
int check_irq_vectors_for_cpu_disable(void)
{
	int irq, cpu;
	unsigned int this_cpu, vector, this_count, count;
	struct irq_desc *desc;
	struct irq_data *data;

	this_cpu = smp_processor_id();
	cpumask_copy(&online_new, cpu_online_mask);
	cpu_clear(this_cpu, online_new);

	this_count = 0;
	for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) {
		irq = __this_cpu_read(vector_irq[vector]);
		if (irq >= 0) {
			desc = irq_to_desc(irq);
			data = irq_desc_get_irq_data(desc);
			cpumask_copy(&affinity_new, data->affinity);
			cpu_clear(this_cpu, affinity_new);

			/* Do not count inactive or per-cpu irqs. */
			if (!irq_has_action(irq) || irqd_is_per_cpu(data))
				continue;

			/*
			 * A single irq may be mapped to multiple
			 * cpu's vector_irq[] (for example IOAPIC cluster
			 * mode).  In this case we have two
			 * possibilities:
			 *
			 * 1) the resulting affinity mask is empty; that is
			 * this the down'd cpu is the last cpu in the irq's
			 * affinity mask, or
			 *
			 * 2) the resulting affinity mask is no longer
			 * a subset of the online cpus but the affinity
			 * mask is not zero; that is the down'd cpu is the
			 * last online cpu in a user set affinity mask.
			 */
			if (cpumask_empty(&affinity_new) ||
			    !cpumask_subset(&affinity_new, &online_new))
				this_count++;
		}
	}

	count = 0;
	for_each_online_cpu(cpu) {
		if (cpu == this_cpu)
			continue;
		for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS;
		     vector++) {
			if (per_cpu(vector_irq, cpu)[vector] < 0)
				count++;
		}
	}

	if (count < this_count) {
		pr_warn("CPU %d disable failed: CPU has %u vectors assigned and there are only %u available.\n",
			this_cpu, this_count, count);
		return -ERANGE;
	}
	return 0;
}

352 353 354
/* A cpu has been removed from cpu_online_mask.  Reset irq affinities. */
void fixup_irqs(void)
{
355
	unsigned int irq, vector;
356 357
	static int warned;
	struct irq_desc *desc;
358
	struct irq_data *data;
359
	struct irq_chip *chip;
360 361 362 363 364 365 366 367 368 369 370 371

	for_each_irq_desc(irq, desc) {
		int break_affinity = 0;
		int set_affinity = 1;
		const struct cpumask *affinity;

		if (!desc)
			continue;
		if (irq == 2)
			continue;

		/* interrupt's are disabled at this point */
372
		raw_spin_lock(&desc->lock);
373

374
		data = irq_desc_get_irq_data(desc);
375
		affinity = data->affinity;
376
		if (!irq_has_action(irq) || irqd_is_per_cpu(data) ||
377
		    cpumask_subset(affinity, cpu_online_mask)) {
378
			raw_spin_unlock(&desc->lock);
379 380 381
			continue;
		}

382 383 384 385 386 387 388
		/*
		 * Complete the irq move. This cpu is going down and for
		 * non intr-remapping case, we can't wait till this interrupt
		 * arrives at this cpu before completing the irq move.
		 */
		irq_force_complete_move(irq);

389 390
		if (cpumask_any_and(affinity, cpu_online_mask) >= nr_cpu_ids) {
			break_affinity = 1;
391
			affinity = cpu_online_mask;
392 393
		}

394 395 396
		chip = irq_data_get_irq_chip(data);
		if (!irqd_can_move_in_process_context(data) && chip->irq_mask)
			chip->irq_mask(data);
397

398 399
		if (chip->irq_set_affinity)
			chip->irq_set_affinity(data, affinity, true);
400 401 402
		else if (!(warned++))
			set_affinity = 0;

403 404 405 406 407
		/*
		 * We unmask if the irq was not marked masked by the
		 * core code. That respects the lazy irq disable
		 * behaviour.
		 */
408
		if (!irqd_can_move_in_process_context(data) &&
409
		    !irqd_irq_masked(data) && chip->irq_unmask)
410
			chip->irq_unmask(data);
411

412
		raw_spin_unlock(&desc->lock);
413 414

		if (break_affinity && set_affinity)
415
			pr_notice("Broke affinity for irq %i\n", irq);
416
		else if (!set_affinity)
417
			pr_notice("Cannot set affinity for irq %i\n", irq);
418 419
	}

420 421 422 423 424 425 426 427 428
	/*
	 * We can remove mdelay() and then send spuriuous interrupts to
	 * new cpu targets for all the irqs that were handled previously by
	 * this cpu. While it works, I have seen spurious interrupt messages
	 * (nothing wrong but still...).
	 *
	 * So for now, retain mdelay(1) and check the IRR and then send those
	 * interrupts to new targets as this cpu is already offlined...
	 */
429
	mdelay(1);
430 431 432 433

	for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) {
		unsigned int irr;

434
		if (__this_cpu_read(vector_irq[vector]) <= VECTOR_UNDEFINED)
435 436 437 438
			continue;

		irr = apic_read(APIC_IRR + (vector / 32 * 0x10));
		if (irr  & (1 << (vector % 32))) {
T
Tejun Heo 已提交
439
			irq = __this_cpu_read(vector_irq[vector]);
440

441
			desc = irq_to_desc(irq);
442 443
			data = irq_desc_get_irq_data(desc);
			chip = irq_data_get_irq_chip(data);
444
			raw_spin_lock(&desc->lock);
445
			if (chip->irq_retrigger) {
446
				chip->irq_retrigger(data);
447 448
				__this_cpu_write(vector_irq[vector], VECTOR_RETRIGGERED);
			}
449
			raw_spin_unlock(&desc->lock);
450
		}
451 452
		if (__this_cpu_read(vector_irq[vector]) != VECTOR_RETRIGGERED)
			__this_cpu_write(vector_irq[vector], VECTOR_UNDEFINED);
453
	}
454 455
}
#endif