Commit 0640b5d5 authored by Philippe Gerum's avatar Philippe Gerum

genirq: ipipe: enable pipelined interrupt management

parent 0b0986c3
......@@ -6,6 +6,7 @@
#include <linux/lockdep.h>
#include <linux/ftrace_irq.h>
#include <linux/vtime.h>
#include <linux/ipipe.h>
#include <asm/hardirq.h>
......@@ -62,6 +63,7 @@ extern void irq_exit(void);
#define nmi_enter() \
do { \
__ipipe_nmi_enter(); \
printk_nmi_enter(); \
lockdep_off(); \
ftrace_nmi_enter(); \
......@@ -80,6 +82,7 @@ extern void irq_exit(void);
ftrace_nmi_exit(); \
lockdep_on(); \
printk_nmi_exit(); \
__ipipe_nmi_exit(); \
} while (0)
#endif /* LINUX_HARDIRQ_H */
......@@ -452,6 +452,11 @@ struct irq_chip {
void (*irq_bus_lock)(struct irq_data *data);
void (*irq_bus_sync_unlock)(struct irq_data *data);
#ifdef CONFIG_IPIPE
void (*irq_move)(struct irq_data *data);
void (*irq_hold)(struct irq_data *data);
void (*irq_release)(struct irq_data *data);
#endif /* CONFIG_IPIPE */
void (*irq_cpu_online)(struct irq_data *data);
void (*irq_cpu_offline)(struct irq_data *data);
......@@ -491,6 +496,7 @@ struct irq_chip {
* IRQCHIP_SKIP_SET_WAKE: Skip chip.irq_set_wake(), for this irq chip
* IRQCHIP_ONESHOT_SAFE: One shot does not require mask/unmask
* IRQCHIP_EOI_THREADED: Chip requires eoi() on unmask in threaded mode
* IRQCHIP_PIPELINE_SAFE: Chip can work in pipelined mode
*/
enum {
IRQCHIP_SET_TYPE_MASKED = (1 << 0),
......@@ -500,6 +506,7 @@ enum {
IRQCHIP_SKIP_SET_WAKE = (1 << 4),
IRQCHIP_ONESHOT_SAFE = (1 << 5),
IRQCHIP_EOI_THREADED = (1 << 6),
IRQCHIP_PIPELINE_SAFE = (1 << 7),
};
#include <linux/irqdesc.h>
......@@ -587,6 +594,11 @@ extern int irq_chip_retrigger_hierarchy(struct irq_data *data);
extern void irq_chip_mask_parent(struct irq_data *data);
extern void irq_chip_unmask_parent(struct irq_data *data);
extern void irq_chip_eoi_parent(struct irq_data *data);
#ifdef CONFIG_IPIPE
extern void irq_chip_hold_parent(struct irq_data *data);
extern void irq_chip_release_parent(struct irq_data *data);
#endif
extern int irq_chip_set_affinity_parent(struct irq_data *data,
const struct cpumask *dest,
bool force);
......@@ -711,7 +723,14 @@ extern int irq_set_irq_type(unsigned int irq, unsigned int type);
extern int irq_set_msi_desc(unsigned int irq, struct msi_desc *entry);
extern int irq_set_msi_desc_off(unsigned int irq_base, unsigned int irq_offset,
struct msi_desc *entry);
extern struct irq_data *irq_get_irq_data(unsigned int irq);
static inline __attribute__((const)) struct irq_data *
irq_get_irq_data(unsigned int irq)
{
struct irq_desc *desc = irq_to_desc(irq);
return desc ? &desc->irq_data : NULL;
}
static inline struct irq_chip *irq_get_chip(unsigned int irq)
{
......@@ -953,7 +972,11 @@ struct irq_chip_type {
* different flow mechanisms (level/edge) for it.
*/
struct irq_chip_generic {
#ifdef CONFIG_IPIPE
ipipe_spinlock_t lock;
#else
raw_spinlock_t lock;
#endif
void __iomem *reg_base;
u32 (*reg_readl)(void __iomem *addr);
void (*reg_writel)(u32 val, void __iomem *addr);
......@@ -1081,18 +1104,28 @@ static inline struct irq_chip_type *irq_data_get_chip_type(struct irq_data *d)
#define IRQ_MSK(n) (u32)((n) < 32 ? ((1 << (n)) - 1) : UINT_MAX)
#ifdef CONFIG_SMP
static inline void irq_gc_lock(struct irq_chip_generic *gc)
static inline unsigned long irq_gc_lock(struct irq_chip_generic *gc)
{
raw_spin_lock(&gc->lock);
unsigned long flags = 0;
raw_spin_lock_irqsave_cond(&gc->lock, flags);
return flags;
}
static inline void irq_gc_unlock(struct irq_chip_generic *gc)
static inline void
irq_gc_unlock(struct irq_chip_generic *gc, unsigned long flags)
{
raw_spin_unlock(&gc->lock);
raw_spin_unlock_irqrestore_cond(&gc->lock, flags);
}
#else
static inline void irq_gc_lock(struct irq_chip_generic *gc) { }
static inline void irq_gc_unlock(struct irq_chip_generic *gc) { }
static inline unsigned long irq_gc_lock(struct irq_chip_generic *gc)
{
return hard_cond_local_irq_save();
}
static inline void
irq_gc_unlock(struct irq_chip_generic *gc, unsigned long flags)
{
hard_cond_local_irq_restore(flags);
}
#endif
/*
......
......@@ -56,6 +56,10 @@ struct irq_desc {
struct irq_common_data irq_common_data;
struct irq_data irq_data;
unsigned int __percpu *kstat_irqs;
#ifdef CONFIG_IPIPE
void (*ipipe_ack)(struct irq_desc *desc);
void (*ipipe_end)(struct irq_desc *desc);
#endif /* CONFIG_IPIPE */
irq_flow_handler_t handle_irq;
#ifdef CONFIG_IRQ_PREFLOW_FASTEOI
irq_preflow_handler_t preflow_handler;
......@@ -183,6 +187,10 @@ static inline int irq_desc_has_action(struct irq_desc *desc)
return desc->action != NULL;
}
irq_flow_handler_t
__fixup_irq_handler(struct irq_desc *desc, irq_flow_handler_t handle,
int is_chained);
static inline int irq_has_action(unsigned int irq)
{
return irq_desc_has_action(irq_to_desc(irq));
......
......@@ -6,7 +6,11 @@
extern int nr_irqs;
#if !defined(CONFIG_IPIPE) || defined(CONFIG_SPARSE_IRQ)
extern struct irq_desc *irq_to_desc(unsigned int irq);
#else
#define irq_to_desc(irq) ({ ipipe_virtual_irq_p(irq) ? NULL : &irq_desc[irq]; })
#endif
unsigned int irq_get_next_irq(unsigned int offset);
# define for_each_irq_desc(irq, desc) \
......
This diff is collapsed.
......@@ -42,7 +42,7 @@ struct irq_chip no_irq_chip = {
.irq_enable = noop,
.irq_disable = noop,
.irq_ack = ack_bad,
.flags = IRQCHIP_SKIP_SET_WAKE,
.flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_PIPELINE_SAFE,
};
/*
......@@ -58,6 +58,6 @@ struct irq_chip dummy_irq_chip = {
.irq_ack = noop,
.irq_mask = noop,
.irq_unmask = noop,
.flags = IRQCHIP_SKIP_SET_WAKE,
.flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_PIPELINE_SAFE,
};
EXPORT_SYMBOL_GPL(dummy_irq_chip);
......@@ -36,12 +36,13 @@ void irq_gc_mask_disable_reg(struct irq_data *d)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
struct irq_chip_type *ct = irq_data_get_chip_type(d);
unsigned long flags;
u32 mask = d->mask;
irq_gc_lock(gc);
flags = irq_gc_lock(gc);
irq_reg_writel(gc, mask, ct->regs.disable);
*ct->mask_cache &= ~mask;
irq_gc_unlock(gc);
irq_gc_unlock(gc, flags);
}
/**
......@@ -55,12 +56,13 @@ void irq_gc_mask_set_bit(struct irq_data *d)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
struct irq_chip_type *ct = irq_data_get_chip_type(d);
unsigned long flags;
u32 mask = d->mask;
irq_gc_lock(gc);
flags = irq_gc_lock(gc);
*ct->mask_cache |= mask;
irq_reg_writel(gc, *ct->mask_cache, ct->regs.mask);
irq_gc_unlock(gc);
irq_gc_unlock(gc, flags);
}
EXPORT_SYMBOL_GPL(irq_gc_mask_set_bit);
......@@ -75,12 +77,13 @@ void irq_gc_mask_clr_bit(struct irq_data *d)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
struct irq_chip_type *ct = irq_data_get_chip_type(d);
unsigned long flags;
u32 mask = d->mask;
irq_gc_lock(gc);
flags = irq_gc_lock(gc);
*ct->mask_cache &= ~mask;
irq_reg_writel(gc, *ct->mask_cache, ct->regs.mask);
irq_gc_unlock(gc);
irq_gc_unlock(gc, flags);
}
EXPORT_SYMBOL_GPL(irq_gc_mask_clr_bit);
......@@ -95,12 +98,13 @@ void irq_gc_unmask_enable_reg(struct irq_data *d)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
struct irq_chip_type *ct = irq_data_get_chip_type(d);
unsigned long flags;
u32 mask = d->mask;
irq_gc_lock(gc);
flags = irq_gc_lock(gc);
irq_reg_writel(gc, mask, ct->regs.enable);
*ct->mask_cache |= mask;
irq_gc_unlock(gc);
irq_gc_unlock(gc, flags);
}
/**
......@@ -111,11 +115,12 @@ void irq_gc_ack_set_bit(struct irq_data *d)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
struct irq_chip_type *ct = irq_data_get_chip_type(d);
unsigned long flags;
u32 mask = d->mask;
irq_gc_lock(gc);
flags = irq_gc_lock(gc);
irq_reg_writel(gc, mask, ct->regs.ack);
irq_gc_unlock(gc);
irq_gc_unlock(gc, flags);
}
EXPORT_SYMBOL_GPL(irq_gc_ack_set_bit);
......@@ -127,11 +132,12 @@ void irq_gc_ack_clr_bit(struct irq_data *d)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
struct irq_chip_type *ct = irq_data_get_chip_type(d);
unsigned long flags;
u32 mask = ~d->mask;
irq_gc_lock(gc);
flags = irq_gc_lock(gc);
irq_reg_writel(gc, mask, ct->regs.ack);
irq_gc_unlock(gc);
irq_gc_unlock(gc, flags);
}
/**
......@@ -150,13 +156,14 @@ void irq_gc_mask_disable_and_ack_set(struct irq_data *d)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
struct irq_chip_type *ct = irq_data_get_chip_type(d);
unsigned long flags;
u32 mask = d->mask;
irq_gc_lock(gc);
flags = irq_gc_lock(gc);
irq_reg_writel(gc, mask, ct->regs.disable);
*ct->mask_cache &= ~mask;
irq_reg_writel(gc, mask, ct->regs.ack);
irq_gc_unlock(gc);
irq_gc_unlock(gc, flags);
}
/**
......@@ -167,11 +174,12 @@ void irq_gc_eoi(struct irq_data *d)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
struct irq_chip_type *ct = irq_data_get_chip_type(d);
unsigned long flags;
u32 mask = d->mask;
irq_gc_lock(gc);
flags = irq_gc_lock(gc);
irq_reg_writel(gc, mask, ct->regs.eoi);
irq_gc_unlock(gc);
irq_gc_unlock(gc, flags);
}
/**
......@@ -186,17 +194,18 @@ void irq_gc_eoi(struct irq_data *d)
int irq_gc_set_wake(struct irq_data *d, unsigned int on)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
unsigned long flags;
u32 mask = d->mask;
if (!(mask & gc->wake_enabled))
return -EINVAL;
irq_gc_lock(gc);
flags = irq_gc_lock(gc);
if (on)
gc->wake_active |= mask;
else
gc->wake_active &= ~mask;
irq_gc_unlock(gc);
irq_gc_unlock(gc, flags);
return 0;
}
......
......@@ -60,6 +60,7 @@ enum {
IRQS_PENDING = 0x00000200,
IRQS_SUSPENDED = 0x00000800,
IRQS_TIMINGS = 0x00001000,
IPIPE_IRQS_NEEDS_STARTUP= 0x80000000,
};
#include "debug.h"
......
......@@ -126,6 +126,9 @@ static void desc_set_defaults(unsigned int irq, struct irq_desc *desc, int node,
for_each_possible_cpu(cpu)
*per_cpu_ptr(desc->kstat_irqs, cpu) = 0;
desc_smp_init(desc, node, affinity);
#ifdef CONFIG_IPIPE
desc->istate |= IPIPE_IRQS_NEEDS_STARTUP;
#endif
}
int nr_irqs = NR_IRQS;
......@@ -541,11 +544,13 @@ int __init early_irq_init(void)
return arch_early_irq_init();
}
#ifndef CONFIG_IPIPE
struct irq_desc *irq_to_desc(unsigned int irq)
{
return (irq < NR_IRQS) ? irq_desc + irq : NULL;
}
EXPORT_SYMBOL(irq_to_desc);
#endif /* CONFIG_IPIPE */
static void free_desc(unsigned int irq)
{
......
......@@ -818,9 +818,14 @@ again:
desc->threads_oneshot &= ~action->thread_mask;
#ifndef CONFIG_IPIPE
if (!desc->threads_oneshot && !irqd_irq_disabled(&desc->irq_data) &&
irqd_irq_masked(&desc->irq_data))
unmask_threaded_irq(desc);
#else /* CONFIG_IPIPE */
if (!desc->threads_oneshot && !irqd_irq_disabled(&desc->irq_data))
desc->ipipe_end(desc);
#endif /* CONFIG_IPIPE */
out_unlock:
raw_spin_unlock_irq(&desc->lock);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment