Commit e26a4331 authored by Catalin Marinas's avatar Catalin Marinas
Browse files
* 'irq/generic-nmi' of git://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms:
  irqdesc: Add domain handler for NMIs
  genirq: Provide NMI handlers
  genirq: Provide NMI management for percpu_devid interrupts
  genirq: Provide basic NMI management for interrupt lines
parents 8aa67d18 6e4933a0
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -156,6 +156,10 @@ __request_percpu_irq(unsigned int irq, irq_handler_t handler,
		     unsigned long flags, const char *devname,
		     void __percpu *percpu_dev_id);

extern int __must_check
request_nmi(unsigned int irq, irq_handler_t handler, unsigned long flags,
	    const char *name, void *dev);

static inline int __must_check
request_percpu_irq(unsigned int irq, irq_handler_t handler,
		   const char *devname, void __percpu *percpu_dev_id)
@@ -164,9 +168,16 @@ request_percpu_irq(unsigned int irq, irq_handler_t handler,
				    devname, percpu_dev_id);
}

extern int __must_check
request_percpu_nmi(unsigned int irq, irq_handler_t handler,
		   const char *devname, void __percpu *dev);

extern const void *free_irq(unsigned int, void *);
extern void free_percpu_irq(unsigned int, void __percpu *);

extern const void *free_nmi(unsigned int irq, void *dev_id);
extern void free_percpu_nmi(unsigned int irq, void __percpu *percpu_dev_id);

struct device;

extern int __must_check
@@ -217,6 +228,13 @@ extern void enable_percpu_irq(unsigned int irq, unsigned int type);
extern bool irq_percpu_is_enabled(unsigned int irq);
extern void irq_wake_thread(unsigned int irq, void *dev_id);

extern void disable_nmi_nosync(unsigned int irq);
extern void disable_percpu_nmi(unsigned int irq);
extern void enable_nmi(unsigned int irq);
extern void enable_percpu_nmi(unsigned int irq, unsigned int type);
extern int prepare_percpu_nmi(unsigned int irq);
extern void teardown_percpu_nmi(unsigned int irq);

/* The following three functions are for the core kernel use only. */
extern void suspend_device_irqs(void);
extern void resume_device_irqs(void);
+10 −0
Original line number Diff line number Diff line
@@ -442,6 +442,8 @@ static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d)
 * @irq_set_vcpu_affinity:	optional to target a vCPU in a virtual machine
 * @ipi_send_single:	send a single IPI to destination cpus
 * @ipi_send_mask:	send an IPI to destination cpus in cpumask
 * @irq_nmi_setup:	function called from core code before enabling an NMI
 * @irq_nmi_teardown:	function called from core code after disabling an NMI
 * @flags:		chip specific flags
 */
struct irq_chip {
@@ -490,6 +492,9 @@ struct irq_chip {
	void		(*ipi_send_single)(struct irq_data *data, unsigned int cpu);
	void		(*ipi_send_mask)(struct irq_data *data, const struct cpumask *dest);

	int		(*irq_nmi_setup)(struct irq_data *data);
	void		(*irq_nmi_teardown)(struct irq_data *data);

	unsigned long	flags;
};

@@ -505,6 +510,7 @@ struct irq_chip {
 * IRQCHIP_ONESHOT_SAFE:	One shot does not require mask/unmask
 * IRQCHIP_EOI_THREADED:	Chip requires eoi() on unmask in threaded mode
 * IRQCHIP_SUPPORTS_LEVEL_MSI	Chip can provide two doorbells for Level MSIs
 * IRQCHIP_SUPPORTS_NMI:	Chip can deliver NMIs, only for root irqchips
 */
enum {
	IRQCHIP_SET_TYPE_MASKED		= (1 <<  0),
@@ -515,6 +521,7 @@ enum {
	IRQCHIP_ONESHOT_SAFE		= (1 <<  5),
	IRQCHIP_EOI_THREADED		= (1 <<  6),
	IRQCHIP_SUPPORTS_LEVEL_MSI	= (1 <<  7),
	IRQCHIP_SUPPORTS_NMI		= (1 <<  8),
};

#include <linux/irqdesc.h>
@@ -594,6 +601,9 @@ extern void handle_percpu_devid_irq(struct irq_desc *desc);
extern void handle_bad_irq(struct irq_desc *desc);
extern void handle_nested_irq(unsigned int irq);

extern void handle_fasteoi_nmi(struct irq_desc *desc);
extern void handle_percpu_devid_fasteoi_nmi(struct irq_desc *desc);

extern int irq_chip_compose_msi_msg(struct irq_data *data, struct msi_msg *msg);
extern int irq_chip_pm_get(struct irq_data *data);
extern int irq_chip_pm_put(struct irq_data *data);
+5 −0
Original line number Diff line number Diff line
@@ -171,6 +171,11 @@ static inline int handle_domain_irq(struct irq_domain *domain,
{
	return __handle_domain_irq(domain, hwirq, true, regs);
}

#ifdef CONFIG_IRQ_DOMAIN
int handle_domain_nmi(struct irq_domain *domain, unsigned int hwirq,
		      struct pt_regs *regs);
#endif
#endif

/* Test to see if a driver has successfully requested an irq */
+54 −0
Original line number Diff line number Diff line
@@ -729,6 +729,37 @@ out:
}
EXPORT_SYMBOL_GPL(handle_fasteoi_irq);

/**
 *	handle_fasteoi_nmi - irq handler for NMI interrupt lines
 *	@desc:	the interrupt description structure for this irq
 *
 *	A simple NMI-safe handler, considering the restrictions
 *	from request_nmi.
 *
 *	Only a single callback will be issued to the chip: an ->eoi()
 *	call when the interrupt has been serviced. This enables support
 *	for modern forms of interrupt handlers, which handle the flow
 *	details in hardware, transparently.
 */
void handle_fasteoi_nmi(struct irq_desc *desc)
{
	struct irq_chip *chip = irq_desc_get_chip(desc);
	struct irqaction *action = desc->action;
	unsigned int irq = irq_desc_get_irq(desc);
	irqreturn_t res;

	trace_irq_handler_entry(irq, action);
	/*
	 * NMIs cannot be shared, there is only one action.
	 */
	res = action->handler(irq, action->dev_id);
	trace_irq_handler_exit(irq, action, res);

	if (chip->irq_eoi)
		chip->irq_eoi(&desc->irq_data);
}
EXPORT_SYMBOL_GPL(handle_fasteoi_nmi);

/**
 *	handle_edge_irq - edge type IRQ handler
 *	@desc:	the interrupt description structure for this irq
@@ -908,6 +939,29 @@ void handle_percpu_devid_irq(struct irq_desc *desc)
		chip->irq_eoi(&desc->irq_data);
}

/**
 * handle_percpu_devid_fasteoi_nmi - Per CPU local NMI handler with per cpu
 *				     dev ids
 * @desc:	the interrupt description structure for this irq
 *
 * Similar to handle_fasteoi_nmi, but handling the dev_id cookie
 * as a percpu pointer.
 */
void handle_percpu_devid_fasteoi_nmi(struct irq_desc *desc)
{
	struct irq_chip *chip = irq_desc_get_chip(desc);
	struct irqaction *action = desc->action;
	unsigned int irq = irq_desc_get_irq(desc);
	irqreturn_t res;

	trace_irq_handler_entry(irq, action);
	res = action->handler(irq, raw_cpu_ptr(action->percpu_dev_id));
	trace_irq_handler_exit(irq, action, res);

	if (chip->irq_eoi)
		chip->irq_eoi(&desc->irq_data);
}

static void
__irq_do_set_handler(struct irq_desc *desc, irq_flow_handler_t handle,
		     int is_chained, const char *name)
+4 −2
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@ static const struct irq_bit_descr irqchip_flags[] = {
	BIT_MASK_DESCR(IRQCHIP_ONESHOT_SAFE),
	BIT_MASK_DESCR(IRQCHIP_EOI_THREADED),
	BIT_MASK_DESCR(IRQCHIP_SUPPORTS_LEVEL_MSI),
	BIT_MASK_DESCR(IRQCHIP_SUPPORTS_NMI),
};

static void
@@ -140,6 +141,7 @@ static const struct irq_bit_descr irqdesc_istates[] = {
	BIT_MASK_DESCR(IRQS_WAITING),
	BIT_MASK_DESCR(IRQS_PENDING),
	BIT_MASK_DESCR(IRQS_SUSPENDED),
	BIT_MASK_DESCR(IRQS_NMI),
};


@@ -203,8 +205,8 @@ static ssize_t irq_debug_write(struct file *file, const char __user *user_buf,
		chip_bus_lock(desc);
		raw_spin_lock_irqsave(&desc->lock, flags);

		if (irq_settings_is_level(desc)) {
			/* Can't do level, sorry */
		if (irq_settings_is_level(desc) || desc->istate & IRQS_NMI) {
			/* Can't do level nor NMIs, sorry */
			err = -EINVAL;
		} else {
			desc->istate |= IRQS_PENDING;
Loading