summaryrefslogtreecommitdiffstats
path: root/kernel/irq/manage.c
diff options
context:
space:
mode:
authorJulien Thierry <julien.thierry@arm.com>2019-01-31 09:53:59 -0500
committerMarc Zyngier <marc.zyngier@arm.com>2019-02-05 09:36:58 -0500
commit4b078c3f1a26487c39363089ba0d5c6b09f2a89f (patch)
tree3536174761fea16583c3e365501f7e812e6f6529 /kernel/irq/manage.c
parentb525903c254dab2491410f0f23707691b7c2c317 (diff)
genirq: Provide NMI management for percpu_devid interrupts
Add support for percpu_devid interrupts treated as NMIs. Percpu_devid NMIs need to be setup/torn down on each CPU they target. The same restrictions as for global NMIs still apply for percpu_devid NMIs. Signed-off-by: Julien Thierry <julien.thierry@arm.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Ingo Molnar <mingo@kernel.org> Cc: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Diffstat (limited to 'kernel/irq/manage.c')
-rw-r--r--kernel/irq/manage.c177
1 files changed, 177 insertions, 0 deletions
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 9472ae987946..0a1ebc004a59 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -2182,6 +2182,11 @@ out:
2182} 2182}
2183EXPORT_SYMBOL_GPL(enable_percpu_irq); 2183EXPORT_SYMBOL_GPL(enable_percpu_irq);
2184 2184
2185void enable_percpu_nmi(unsigned int irq, unsigned int type)
2186{
2187 enable_percpu_irq(irq, type);
2188}
2189
2185/** 2190/**
2186 * irq_percpu_is_enabled - Check whether the per cpu irq is enabled 2191 * irq_percpu_is_enabled - Check whether the per cpu irq is enabled
2187 * @irq: Linux irq number to check for 2192 * @irq: Linux irq number to check for
@@ -2221,6 +2226,11 @@ void disable_percpu_irq(unsigned int irq)
2221} 2226}
2222EXPORT_SYMBOL_GPL(disable_percpu_irq); 2227EXPORT_SYMBOL_GPL(disable_percpu_irq);
2223 2228
2229void disable_percpu_nmi(unsigned int irq)
2230{
2231 disable_percpu_irq(irq);
2232}
2233
2224/* 2234/*
2225 * Internal function to unregister a percpu irqaction. 2235 * Internal function to unregister a percpu irqaction.
2226 */ 2236 */
@@ -2252,6 +2262,8 @@ static struct irqaction *__free_percpu_irq(unsigned int irq, void __percpu *dev_
2252 /* Found it - now remove it from the list of entries: */ 2262 /* Found it - now remove it from the list of entries: */
2253 desc->action = NULL; 2263 desc->action = NULL;
2254 2264
2265 desc->istate &= ~IRQS_NMI;
2266
2255 raw_spin_unlock_irqrestore(&desc->lock, flags); 2267 raw_spin_unlock_irqrestore(&desc->lock, flags);
2256 2268
2257 unregister_handler_proc(irq, action); 2269 unregister_handler_proc(irq, action);
@@ -2305,6 +2317,19 @@ void free_percpu_irq(unsigned int irq, void __percpu *dev_id)
2305} 2317}
2306EXPORT_SYMBOL_GPL(free_percpu_irq); 2318EXPORT_SYMBOL_GPL(free_percpu_irq);
2307 2319
2320void free_percpu_nmi(unsigned int irq, void __percpu *dev_id)
2321{
2322 struct irq_desc *desc = irq_to_desc(irq);
2323
2324 if (!desc || !irq_settings_is_per_cpu_devid(desc))
2325 return;
2326
2327 if (WARN_ON(!(desc->istate & IRQS_NMI)))
2328 return;
2329
2330 kfree(__free_percpu_irq(irq, dev_id));
2331}
2332
2308/** 2333/**
2309 * setup_percpu_irq - setup a per-cpu interrupt 2334 * setup_percpu_irq - setup a per-cpu interrupt
2310 * @irq: Interrupt line to setup 2335 * @irq: Interrupt line to setup
@@ -2395,6 +2420,158 @@ int __request_percpu_irq(unsigned int irq, irq_handler_t handler,
2395EXPORT_SYMBOL_GPL(__request_percpu_irq); 2420EXPORT_SYMBOL_GPL(__request_percpu_irq);
2396 2421
2397/** 2422/**
2423 * request_percpu_nmi - allocate a percpu interrupt line for NMI delivery
2424 * @irq: Interrupt line to allocate
2425 * @handler: Function to be called when the IRQ occurs.
2426 * @name: An ascii name for the claiming device
2427 * @dev_id: A percpu cookie passed back to the handler function
2428 *
2429 * This call allocates interrupt resources for a per CPU NMI. Per CPU NMIs
2430 * have to be setup on each CPU by calling ready_percpu_nmi() before being
2431 * enabled on the same CPU by using enable_percpu_nmi().
2432 *
2433 * Dev_id must be globally unique. It is a per-cpu variable, and
2434 * the handler gets called with the interrupted CPU's instance of
2435 * that variable.
2436 *
2437 * Interrupt lines requested for NMI delivering should have auto enabling
2438 * setting disabled.
2439 *
2440 * If the interrupt line cannot be used to deliver NMIs, function
2441 * will fail returning a negative value.
2442 */
2443int request_percpu_nmi(unsigned int irq, irq_handler_t handler,
2444 const char *name, void __percpu *dev_id)
2445{
2446 struct irqaction *action;
2447 struct irq_desc *desc;
2448 unsigned long flags;
2449 int retval;
2450
2451 if (!handler)
2452 return -EINVAL;
2453
2454 desc = irq_to_desc(irq);
2455
2456 if (!desc || !irq_settings_can_request(desc) ||
2457 !irq_settings_is_per_cpu_devid(desc) ||
2458 irq_settings_can_autoenable(desc) ||
2459 !irq_supports_nmi(desc))
2460 return -EINVAL;
2461
2462 /* The line cannot already be NMI */
2463 if (desc->istate & IRQS_NMI)
2464 return -EINVAL;
2465
2466 action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
2467 if (!action)
2468 return -ENOMEM;
2469
2470 action->handler = handler;
2471 action->flags = IRQF_PERCPU | IRQF_NO_SUSPEND | IRQF_NO_THREAD
2472 | IRQF_NOBALANCING;
2473 action->name = name;
2474 action->percpu_dev_id = dev_id;
2475
2476 retval = irq_chip_pm_get(&desc->irq_data);
2477 if (retval < 0)
2478 goto err_out;
2479
2480 retval = __setup_irq(irq, desc, action);
2481 if (retval)
2482 goto err_irq_setup;
2483
2484 raw_spin_lock_irqsave(&desc->lock, flags);
2485 desc->istate |= IRQS_NMI;
2486 raw_spin_unlock_irqrestore(&desc->lock, flags);
2487
2488 return 0;
2489
2490err_irq_setup:
2491 irq_chip_pm_put(&desc->irq_data);
2492err_out:
2493 kfree(action);
2494
2495 return retval;
2496}
2497
2498/**
2499 * prepare_percpu_nmi - performs CPU local setup for NMI delivery
2500 * @irq: Interrupt line to prepare for NMI delivery
2501 *
2502 * This call prepares an interrupt line to deliver NMI on the current CPU,
2503 * before that interrupt line gets enabled with enable_percpu_nmi().
2504 *
2505 * As a CPU local operation, this should be called from non-preemptible
2506 * context.
2507 *
2508 * If the interrupt line cannot be used to deliver NMIs, function
2509 * will fail returning a negative value.
2510 */
2511int prepare_percpu_nmi(unsigned int irq)
2512{
2513 unsigned long flags;
2514 struct irq_desc *desc;
2515 int ret = 0;
2516
2517 WARN_ON(preemptible());
2518
2519 desc = irq_get_desc_lock(irq, &flags,
2520 IRQ_GET_DESC_CHECK_PERCPU);
2521 if (!desc)
2522 return -EINVAL;
2523
2524 if (WARN(!(desc->istate & IRQS_NMI),
2525 KERN_ERR "prepare_percpu_nmi called for a non-NMI interrupt: irq %u\n",
2526 irq)) {
2527 ret = -EINVAL;
2528 goto out;
2529 }
2530
2531 ret = irq_nmi_setup(desc);
2532 if (ret) {
2533 pr_err("Failed to setup NMI delivery: irq %u\n", irq);
2534 goto out;
2535 }
2536
2537out:
2538 irq_put_desc_unlock(desc, flags);
2539 return ret;
2540}
2541
2542/**
2543 * teardown_percpu_nmi - undoes NMI setup of IRQ line
2544 * @irq: Interrupt line from which CPU local NMI configuration should be
2545 * removed
2546 *
2547 * This call undoes the setup done by prepare_percpu_nmi().
2548 *
2549 * IRQ line should not be enabled for the current CPU.
2550 *
2551 * As a CPU local operation, this should be called from non-preemptible
2552 * context.
2553 */
2554void teardown_percpu_nmi(unsigned int irq)
2555{
2556 unsigned long flags;
2557 struct irq_desc *desc;
2558
2559 WARN_ON(preemptible());
2560
2561 desc = irq_get_desc_lock(irq, &flags,
2562 IRQ_GET_DESC_CHECK_PERCPU);
2563 if (!desc)
2564 return;
2565
2566 if (WARN_ON(!(desc->istate & IRQS_NMI)))
2567 goto out;
2568
2569 irq_nmi_teardown(desc);
2570out:
2571 irq_put_desc_unlock(desc, flags);
2572}
2573
2574/**
2398 * irq_get_irqchip_state - returns the irqchip state of a interrupt. 2575 * irq_get_irqchip_state - returns the irqchip state of a interrupt.
2399 * @irq: Interrupt line that is forwarded to a VM 2576 * @irq: Interrupt line that is forwarded to a VM
2400 * @which: One of IRQCHIP_STATE_* the caller wants to know about 2577 * @which: One of IRQCHIP_STATE_* the caller wants to know about