cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

resend.c (4507B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar
      4 * Copyright (C) 2005-2006, Thomas Gleixner
      5 *
      6 * This file contains the IRQ-resend code
      7 *
      8 * If the interrupt is waiting to be processed, we try to re-run it.
      9 * We can't directly run it from here since the caller might be in an
     10 * interrupt-protected region. Not all irq controller chips can
     11 * retrigger interrupts at the hardware level, so in those cases
     12 * we allow the resending of IRQs via a tasklet.
     13 */
     14
     15#include <linux/irq.h>
     16#include <linux/module.h>
     17#include <linux/random.h>
     18#include <linux/interrupt.h>
     19
     20#include "internals.h"
     21
     22#ifdef CONFIG_HARDIRQS_SW_RESEND
     23
     24/* Bitmap to handle software resend of interrupts: */
     25static DECLARE_BITMAP(irqs_resend, IRQ_BITMAP_BITS);
     26
     27/*
     28 * Run software resends of IRQ's
     29 */
     30static void resend_irqs(struct tasklet_struct *unused)
     31{
     32	struct irq_desc *desc;
     33	int irq;
     34
     35	while (!bitmap_empty(irqs_resend, nr_irqs)) {
     36		irq = find_first_bit(irqs_resend, nr_irqs);
     37		clear_bit(irq, irqs_resend);
     38		desc = irq_to_desc(irq);
     39		if (!desc)
     40			continue;
     41		local_irq_disable();
     42		desc->handle_irq(desc);
     43		local_irq_enable();
     44	}
     45}
     46
     47/* Tasklet to handle resend: */
     48static DECLARE_TASKLET(resend_tasklet, resend_irqs);
     49
     50static int irq_sw_resend(struct irq_desc *desc)
     51{
     52	unsigned int irq = irq_desc_get_irq(desc);
     53
     54	/*
     55	 * Validate whether this interrupt can be safely injected from
     56	 * non interrupt context
     57	 */
     58	if (handle_enforce_irqctx(&desc->irq_data))
     59		return -EINVAL;
     60
     61	/*
     62	 * If the interrupt is running in the thread context of the parent
     63	 * irq we need to be careful, because we cannot trigger it
     64	 * directly.
     65	 */
     66	if (irq_settings_is_nested_thread(desc)) {
     67		/*
     68		 * If the parent_irq is valid, we retrigger the parent,
     69		 * otherwise we do nothing.
     70		 */
     71		if (!desc->parent_irq)
     72			return -EINVAL;
     73		irq = desc->parent_irq;
     74	}
     75
     76	/* Set it pending and activate the softirq: */
     77	set_bit(irq, irqs_resend);
     78	tasklet_schedule(&resend_tasklet);
     79	return 0;
     80}
     81
     82#else
     83static int irq_sw_resend(struct irq_desc *desc)
     84{
     85	return -EINVAL;
     86}
     87#endif
     88
     89static int try_retrigger(struct irq_desc *desc)
     90{
     91	if (desc->irq_data.chip->irq_retrigger)
     92		return desc->irq_data.chip->irq_retrigger(&desc->irq_data);
     93
     94#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
     95	return irq_chip_retrigger_hierarchy(&desc->irq_data);
     96#else
     97	return 0;
     98#endif
     99}
    100
    101/*
    102 * IRQ resend
    103 *
    104 * Is called with interrupts disabled and desc->lock held.
    105 */
    106int check_irq_resend(struct irq_desc *desc, bool inject)
    107{
    108	int err = 0;
    109
    110	/*
    111	 * We do not resend level type interrupts. Level type interrupts
    112	 * are resent by hardware when they are still active. Clear the
    113	 * pending bit so suspend/resume does not get confused.
    114	 */
    115	if (irq_settings_is_level(desc)) {
    116		desc->istate &= ~IRQS_PENDING;
    117		return -EINVAL;
    118	}
    119
    120	if (desc->istate & IRQS_REPLAY)
    121		return -EBUSY;
    122
    123	if (!(desc->istate & IRQS_PENDING) && !inject)
    124		return 0;
    125
    126	desc->istate &= ~IRQS_PENDING;
    127
    128	if (!try_retrigger(desc))
    129		err = irq_sw_resend(desc);
    130
    131	/* If the retrigger was successful, mark it with the REPLAY bit */
    132	if (!err)
    133		desc->istate |= IRQS_REPLAY;
    134	return err;
    135}
    136
    137#ifdef CONFIG_GENERIC_IRQ_INJECTION
    138/**
    139 * irq_inject_interrupt - Inject an interrupt for testing/error injection
    140 * @irq:	The interrupt number
    141 *
    142 * This function must only be used for debug and testing purposes!
    143 *
    144 * Especially on x86 this can cause a premature completion of an interrupt
    145 * affinity change causing the interrupt line to become stale. Very
    146 * unlikely, but possible.
    147 *
    148 * The injection can fail for various reasons:
    149 * - Interrupt is not activated
    150 * - Interrupt is NMI type or currently replaying
    151 * - Interrupt is level type
    152 * - Interrupt does not support hardware retrigger and software resend is
    153 *   either not enabled or not possible for the interrupt.
    154 */
    155int irq_inject_interrupt(unsigned int irq)
    156{
    157	struct irq_desc *desc;
    158	unsigned long flags;
    159	int err;
    160
    161	/* Try the state injection hardware interface first */
    162	if (!irq_set_irqchip_state(irq, IRQCHIP_STATE_PENDING, true))
    163		return 0;
    164
    165	/* That failed, try via the resend mechanism */
    166	desc = irq_get_desc_buslock(irq, &flags, 0);
    167	if (!desc)
    168		return -EINVAL;
    169
    170	/*
    171	 * Only try to inject when the interrupt is:
    172	 *  - not NMI type
    173	 *  - activated
    174	 */
    175	if ((desc->istate & IRQS_NMI) || !irqd_is_activated(&desc->irq_data))
    176		err = -EINVAL;
    177	else
    178		err = check_irq_resend(desc, true);
    179
    180	irq_put_desc_busunlock(desc, flags);
    181	return err;
    182}
    183EXPORT_SYMBOL_GPL(irq_inject_interrupt);
    184#endif