linux/kernel/irq/generic-chip.c
<<
>>
Prefs
   1/*
   2 * Library implementing the most common irq chip callback functions
   3 *
   4 * Copyright (C) 2011, Thomas Gleixner
   5 */
   6#include <linux/io.h>
   7#include <linux/irq.h>
   8#include <linux/slab.h>
   9#include <linux/export.h>
  10#include <linux/interrupt.h>
  11#include <linux/kernel_stat.h>
  12#include <linux/syscore_ops.h>
  13
  14#include "internals.h"
  15
  16static LIST_HEAD(gc_list);
  17static DEFINE_RAW_SPINLOCK(gc_lock);
  18
  19static inline struct irq_chip_regs *cur_regs(struct irq_data *d)
  20{
  21        return &container_of(d->chip, struct irq_chip_type, chip)->regs;
  22}
  23
  24/**
  25 * irq_gc_noop - NOOP function
  26 * @d: irq_data
  27 */
  28void irq_gc_noop(struct irq_data *d)
  29{
  30}
  31
  32/**
  33 * irq_gc_mask_disable_reg - Mask chip via disable register
  34 * @d: irq_data
  35 *
  36 * Chip has separate enable/disable registers instead of a single mask
  37 * register.
  38 */
  39void irq_gc_mask_disable_reg(struct irq_data *d)
  40{
  41        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
  42        u32 mask = 1 << (d->irq - gc->irq_base);
  43
  44        irq_gc_lock(gc);
  45        irq_reg_writel(mask, gc->reg_base + cur_regs(d)->disable);
  46        gc->mask_cache &= ~mask;
  47        irq_gc_unlock(gc);
  48}
  49
  50/**
  51 * irq_gc_mask_set_mask_bit - Mask chip via setting bit in mask register
  52 * @d: irq_data
  53 *
  54 * Chip has a single mask register. Values of this register are cached
  55 * and protected by gc->lock
  56 */
  57void irq_gc_mask_set_bit(struct irq_data *d)
  58{
  59        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
  60        u32 mask = 1 << (d->irq - gc->irq_base);
  61
  62        irq_gc_lock(gc);
  63        gc->mask_cache |= mask;
  64        irq_reg_writel(gc->mask_cache, gc->reg_base + cur_regs(d)->mask);
  65        irq_gc_unlock(gc);
  66}
  67
  68/**
  69 * irq_gc_mask_set_mask_bit - Mask chip via clearing bit in mask register
  70 * @d: irq_data
  71 *
  72 * Chip has a single mask register. Values of this register are cached
  73 * and protected by gc->lock
  74 */
  75void irq_gc_mask_clr_bit(struct irq_data *d)
  76{
  77        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
  78        u32 mask = 1 << (d->irq - gc->irq_base);
  79
  80        irq_gc_lock(gc);
  81        gc->mask_cache &= ~mask;
  82        irq_reg_writel(gc->mask_cache, gc->reg_base + cur_regs(d)->mask);
  83        irq_gc_unlock(gc);
  84}
  85
  86/**
  87 * irq_gc_unmask_enable_reg - Unmask chip via enable register
  88 * @d: irq_data
  89 *
  90 * Chip has separate enable/disable registers instead of a single mask
  91 * register.
  92 */
  93void irq_gc_unmask_enable_reg(struct irq_data *d)
  94{
  95        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
  96        u32 mask = 1 << (d->irq - gc->irq_base);
  97
  98        irq_gc_lock(gc);
  99        irq_reg_writel(mask, gc->reg_base + cur_regs(d)->enable);
 100        gc->mask_cache |= mask;
 101        irq_gc_unlock(gc);
 102}
 103
 104/**
 105 * irq_gc_ack_set_bit - Ack pending interrupt via setting bit
 106 * @d: irq_data
 107 */
 108void irq_gc_ack_set_bit(struct irq_data *d)
 109{
 110        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
 111        u32 mask = 1 << (d->irq - gc->irq_base);
 112
 113        irq_gc_lock(gc);
 114        irq_reg_writel(mask, gc->reg_base + cur_regs(d)->ack);
 115        irq_gc_unlock(gc);
 116}
 117
 118/**
 119 * irq_gc_ack_clr_bit - Ack pending interrupt via clearing bit
 120 * @d: irq_data
 121 */
 122void irq_gc_ack_clr_bit(struct irq_data *d)
 123{
 124        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
 125        u32 mask = ~(1 << (d->irq - gc->irq_base));
 126
 127        irq_gc_lock(gc);
 128        irq_reg_writel(mask, gc->reg_base + cur_regs(d)->ack);
 129        irq_gc_unlock(gc);
 130}
 131
 132/**
 133 * irq_gc_mask_disable_reg_and_ack- Mask and ack pending interrupt
 134 * @d: irq_data
 135 */
 136void irq_gc_mask_disable_reg_and_ack(struct irq_data *d)
 137{
 138        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
 139        u32 mask = 1 << (d->irq - gc->irq_base);
 140
 141        irq_gc_lock(gc);
 142        irq_reg_writel(mask, gc->reg_base + cur_regs(d)->mask);
 143        irq_reg_writel(mask, gc->reg_base + cur_regs(d)->ack);
 144        irq_gc_unlock(gc);
 145}
 146
 147/**
 148 * irq_gc_eoi - EOI interrupt
 149 * @d: irq_data
 150 */
 151void irq_gc_eoi(struct irq_data *d)
 152{
 153        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
 154        u32 mask = 1 << (d->irq - gc->irq_base);
 155
 156        irq_gc_lock(gc);
 157        irq_reg_writel(mask, gc->reg_base + cur_regs(d)->eoi);
 158        irq_gc_unlock(gc);
 159}
 160
 161/**
 162 * irq_gc_set_wake - Set/clr wake bit for an interrupt
 163 * @d: irq_data
 164 *
 165 * For chips where the wake from suspend functionality is not
 166 * configured in a separate register and the wakeup active state is
 167 * just stored in a bitmask.
 168 */
 169int irq_gc_set_wake(struct irq_data *d, unsigned int on)
 170{
 171        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
 172        u32 mask = 1 << (d->irq - gc->irq_base);
 173
 174        if (!(mask & gc->wake_enabled))
 175                return -EINVAL;
 176
 177        irq_gc_lock(gc);
 178        if (on)
 179                gc->wake_active |= mask;
 180        else
 181                gc->wake_active &= ~mask;
 182        irq_gc_unlock(gc);
 183        return 0;
 184}
 185
 186/**
 187 * irq_alloc_generic_chip - Allocate a generic chip and initialize it
 188 * @name:       Name of the irq chip
 189 * @num_ct:     Number of irq_chip_type instances associated with this
 190 * @irq_base:   Interrupt base nr for this chip
 191 * @reg_base:   Register base address (virtual)
 192 * @handler:    Default flow handler associated with this chip
 193 *
 194 * Returns an initialized irq_chip_generic structure. The chip defaults
 195 * to the primary (index 0) irq_chip_type and @handler
 196 */
 197struct irq_chip_generic *
 198irq_alloc_generic_chip(const char *name, int num_ct, unsigned int irq_base,
 199                       void __iomem *reg_base, irq_flow_handler_t handler)
 200{
 201        struct irq_chip_generic *gc;
 202        unsigned long sz = sizeof(*gc) + num_ct * sizeof(struct irq_chip_type);
 203
 204        gc = kzalloc(sz, GFP_KERNEL);
 205        if (gc) {
 206                raw_spin_lock_init(&gc->lock);
 207                gc->num_ct = num_ct;
 208                gc->irq_base = irq_base;
 209                gc->reg_base = reg_base;
 210                gc->chip_types->chip.name = name;
 211                gc->chip_types->handler = handler;
 212        }
 213        return gc;
 214}
 215EXPORT_SYMBOL_GPL(irq_alloc_generic_chip);
 216
 217/*
 218 * Separate lockdep class for interrupt chip which can nest irq_desc
 219 * lock.
 220 */
 221static struct lock_class_key irq_nested_lock_class;
 222
 223/**
 224 * irq_setup_generic_chip - Setup a range of interrupts with a generic chip
 225 * @gc:         Generic irq chip holding all data
 226 * @msk:        Bitmask holding the irqs to initialize relative to gc->irq_base
 227 * @flags:      Flags for initialization
 228 * @clr:        IRQ_* bits to clear
 229 * @set:        IRQ_* bits to set
 230 *
 231 * Set up max. 32 interrupts starting from gc->irq_base. Note, this
 232 * initializes all interrupts to the primary irq_chip_type and its
 233 * associated handler.
 234 */
 235void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk,
 236                            enum irq_gc_flags flags, unsigned int clr,
 237                            unsigned int set)
 238{
 239        struct irq_chip_type *ct = gc->chip_types;
 240        unsigned int i;
 241
 242        raw_spin_lock(&gc_lock);
 243        list_add_tail(&gc->list, &gc_list);
 244        raw_spin_unlock(&gc_lock);
 245
 246        /* Init mask cache ? */
 247        if (flags & IRQ_GC_INIT_MASK_CACHE)
 248                gc->mask_cache = irq_reg_readl(gc->reg_base + ct->regs.mask);
 249
 250        for (i = gc->irq_base; msk; msk >>= 1, i++) {
 251                if (!(msk & 0x01))
 252                        continue;
 253
 254                if (flags & IRQ_GC_INIT_NESTED_LOCK)
 255                        irq_set_lockdep_class(i, &irq_nested_lock_class);
 256
 257                irq_set_chip_and_handler(i, &ct->chip, ct->handler);
 258                irq_set_chip_data(i, gc);
 259                irq_modify_status(i, clr, set);
 260        }
 261        gc->irq_cnt = i - gc->irq_base;
 262}
 263EXPORT_SYMBOL_GPL(irq_setup_generic_chip);
 264
 265/**
 266 * irq_setup_alt_chip - Switch to alternative chip
 267 * @d:          irq_data for this interrupt
 268 * @type        Flow type to be initialized
 269 *
 270 * Only to be called from chip->irq_set_type() callbacks.
 271 */
 272int irq_setup_alt_chip(struct irq_data *d, unsigned int type)
 273{
 274        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
 275        struct irq_chip_type *ct = gc->chip_types;
 276        unsigned int i;
 277
 278        for (i = 0; i < gc->num_ct; i++, ct++) {
 279                if (ct->type & type) {
 280                        d->chip = &ct->chip;
 281                        irq_data_to_desc(d)->handle_irq = ct->handler;
 282                        return 0;
 283                }
 284        }
 285        return -EINVAL;
 286}
 287EXPORT_SYMBOL_GPL(irq_setup_alt_chip);
 288
 289/**
 290 * irq_remove_generic_chip - Remove a chip
 291 * @gc:         Generic irq chip holding all data
 292 * @msk:        Bitmask holding the irqs to initialize relative to gc->irq_base
 293 * @clr:        IRQ_* bits to clear
 294 * @set:        IRQ_* bits to set
 295 *
 296 * Remove up to 32 interrupts starting from gc->irq_base.
 297 */
 298void irq_remove_generic_chip(struct irq_chip_generic *gc, u32 msk,
 299                             unsigned int clr, unsigned int set)
 300{
 301        unsigned int i = gc->irq_base;
 302
 303        raw_spin_lock(&gc_lock);
 304        list_del(&gc->list);
 305        raw_spin_unlock(&gc_lock);
 306
 307        for (; msk; msk >>= 1, i++) {
 308                if (!(msk & 0x01))
 309                        continue;
 310
 311                /* Remove handler first. That will mask the irq line */
 312                irq_set_handler(i, NULL);
 313                irq_set_chip(i, &no_irq_chip);
 314                irq_set_chip_data(i, NULL);
 315                irq_modify_status(i, clr, set);
 316        }
 317}
 318EXPORT_SYMBOL_GPL(irq_remove_generic_chip);
 319
 320#ifdef CONFIG_PM
 321static int irq_gc_suspend(void)
 322{
 323        struct irq_chip_generic *gc;
 324
 325        list_for_each_entry(gc, &gc_list, list) {
 326                struct irq_chip_type *ct = gc->chip_types;
 327
 328                if (ct->chip.irq_suspend)
 329                        ct->chip.irq_suspend(irq_get_irq_data(gc->irq_base));
 330        }
 331        return 0;
 332}
 333
 334static void irq_gc_resume(void)
 335{
 336        struct irq_chip_generic *gc;
 337
 338        list_for_each_entry(gc, &gc_list, list) {
 339                struct irq_chip_type *ct = gc->chip_types;
 340
 341                if (ct->chip.irq_resume)
 342                        ct->chip.irq_resume(irq_get_irq_data(gc->irq_base));
 343        }
 344}
 345#else
 346#define irq_gc_suspend NULL
 347#define irq_gc_resume NULL
 348#endif
 349
 350static void irq_gc_shutdown(void)
 351{
 352        struct irq_chip_generic *gc;
 353
 354        list_for_each_entry(gc, &gc_list, list) {
 355                struct irq_chip_type *ct = gc->chip_types;
 356
 357                if (ct->chip.irq_pm_shutdown)
 358                        ct->chip.irq_pm_shutdown(irq_get_irq_data(gc->irq_base));
 359        }
 360}
 361
 362static struct syscore_ops irq_gc_syscore_ops = {
 363        .suspend = irq_gc_suspend,
 364        .resume = irq_gc_resume,
 365        .shutdown = irq_gc_shutdown,
 366};
 367
 368static int __init irq_gc_init_ops(void)
 369{
 370        register_syscore_ops(&irq_gc_syscore_ops);
 371        return 0;
 372}
 373device_initcall(irq_gc_init_ops);
 374
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.