genirq: Implement a generic interrupt chip
Implement a generic interrupt chip, which is configurable and is able to handle the most common irq chip implementations. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: linux-arm-kernel@lists.infradead.org Tested-by: H Hartley Sweeten <hsweeten@visionengravers.com> Tested-by: Tony Lindgren <tony@atomide.com> Tested-by; Kevin Hilman <khilman@ti.com>
This commit is contained in:
parent
7f1b1244e1
commit
7d82806247
3 changed files with 397 additions and 0 deletions
|
@ -568,6 +568,141 @@ static inline int irq_reserve_irq(unsigned int irq)
|
|||
return irq_reserve_irqs(irq, 1);
|
||||
}
|
||||
|
||||
#ifndef irq_reg_writel
|
||||
# define irq_reg_writel(val, addr) writel(val, addr)
|
||||
#endif
|
||||
#ifndef irq_reg_readl
|
||||
# define irq_reg_readl(addr) readl(addr)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* struct irq_chip_regs - register offsets for struct irq_gci
|
||||
* @enable: Enable register offset to reg_base
|
||||
* @disable: Disable register offset to reg_base
|
||||
* @mask: Mask register offset to reg_base
|
||||
* @ack: Ack register offset to reg_base
|
||||
* @eoi: Eoi register offset to reg_base
|
||||
* @type: Type configuration register offset to reg_base
|
||||
* @polarity: Polarity configuration register offset to reg_base
|
||||
*/
|
||||
struct irq_chip_regs {
|
||||
unsigned long enable;
|
||||
unsigned long disable;
|
||||
unsigned long mask;
|
||||
unsigned long ack;
|
||||
unsigned long eoi;
|
||||
unsigned long type;
|
||||
unsigned long polarity;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct irq_chip_type - Generic interrupt chip instance for a flow type
|
||||
* @chip: The real interrupt chip which provides the callbacks
|
||||
* @regs: Register offsets for this chip
|
||||
* @handler: Flow handler associated with this chip
|
||||
* @type: Chip can handle these flow types
|
||||
*
|
||||
* A irq_generic_chip can have several instances of irq_chip_type when
|
||||
* it requires different functions and register offsets for different
|
||||
* flow types.
|
||||
*/
|
||||
struct irq_chip_type {
|
||||
struct irq_chip chip;
|
||||
struct irq_chip_regs regs;
|
||||
irq_flow_handler_t handler;
|
||||
u32 type;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct irq_chip_generic - Generic irq chip data structure
|
||||
* @lock: Lock to protect register and cache data access
|
||||
* @reg_base: Register base address (virtual)
|
||||
* @irq_base: Interrupt base nr for this chip
|
||||
* @irq_cnt: Number of interrupts handled by this chip
|
||||
* @mask_cache: Cached mask register
|
||||
* @type_cache: Cached type register
|
||||
* @polarity_cache: Cached polarity register
|
||||
* @wake_enabled: Interrupt can wakeup from suspend
|
||||
* @wake_active: Interrupt is marked as an wakeup from suspend source
|
||||
* @num_ct: Number of available irq_chip_type instances (usually 1)
|
||||
* @private: Private data for non generic chip callbacks
|
||||
* @chip_types: Array of interrupt irq_chip_types
|
||||
*
|
||||
* Note, that irq_chip_generic can have multiple irq_chip_type
|
||||
* implementations which can be associated to a particular irq line of
|
||||
* an irq_chip_generic instance. That allows to share and protect
|
||||
* state in an irq_chip_generic instance when we need to implement
|
||||
* different flow mechanisms (level/edge) for it.
|
||||
*/
|
||||
struct irq_chip_generic {
|
||||
raw_spinlock_t lock;
|
||||
void __iomem *reg_base;
|
||||
unsigned int irq_base;
|
||||
unsigned int irq_cnt;
|
||||
u32 mask_cache;
|
||||
u32 type_cache;
|
||||
u32 polarity_cache;
|
||||
u32 wake_enabled;
|
||||
u32 wake_active;
|
||||
unsigned int num_ct;
|
||||
void *private;
|
||||
struct irq_chip_type chip_types[0];
|
||||
};
|
||||
|
||||
/**
|
||||
* enum irq_gc_flags - Initialization flags for generic irq chips
|
||||
* @IRQ_GC_INIT_MASK_CACHE: Initialize the mask_cache by reading mask reg
|
||||
* @IRQ_GC_INIT_NESTED_LOCK: Set the lock class of the irqs to nested for
|
||||
* irq chips which need to call irq_set_wake() on
|
||||
* the parent irq. Usually GPIO implementations
|
||||
*/
|
||||
enum irq_gc_flags {
|
||||
IRQ_GC_INIT_MASK_CACHE = 1 << 0,
|
||||
IRQ_GC_INIT_NESTED_LOCK = 1 << 1,
|
||||
};
|
||||
|
||||
/* Generic chip callback functions */
|
||||
void irq_gc_noop(struct irq_data *d);
|
||||
void irq_gc_mask_disable_reg(struct irq_data *d);
|
||||
void irq_gc_mask_set_bit(struct irq_data *d);
|
||||
void irq_gc_mask_clr_bit(struct irq_data *d);
|
||||
void irq_gc_unmask_enable_reg(struct irq_data *d);
|
||||
void irq_gc_ack(struct irq_data *d);
|
||||
void irq_gc_mask_disable_reg_and_ack(struct irq_data *d);
|
||||
void irq_gc_eoi(struct irq_data *d);
|
||||
int irq_gc_set_wake(struct irq_data *d, unsigned int on);
|
||||
|
||||
/* Setup functions for irq_chip_generic */
|
||||
struct irq_chip_generic *
|
||||
irq_alloc_generic_chip(const char *name, int nr_ct, unsigned int irq_base,
|
||||
void __iomem *reg_base, irq_flow_handler_t handler);
|
||||
void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk,
|
||||
enum irq_gc_flags flags, unsigned int clr,
|
||||
unsigned int set);
|
||||
int irq_setup_alt_chip(struct irq_data *d, unsigned int type);
|
||||
|
||||
static inline struct irq_chip_type *irq_data_get_chip_type(struct irq_data *d)
|
||||
{
|
||||
return container_of(d->chip, struct irq_chip_type, chip);
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
raw_spin_lock(&gc->lock);
|
||||
}
|
||||
|
||||
static inline void irq_gc_unlock(struct irq_chip_generic *gc)
|
||||
{
|
||||
raw_spin_unlock(&gc->lock);
|
||||
}
|
||||
#else
|
||||
static inline void irq_gc_lock(struct irq_chip_generic *gc) { }
|
||||
static inline void irq_gc_unlock(struct irq_chip_generic *gc) { }
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_GENERIC_HARDIRQS */
|
||||
|
||||
#endif /* !CONFIG_S390 */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue