linux/drivers/sh/intc.c
<<
>>
Prefs
   1/*
   2 * Shared interrupt handling code for IPR and INTC2 types of IRQs.
   3 *
   4 * Copyright (C) 2007, 2008 Magnus Damm
   5 *
   6 * Based on intc2.c and ipr.c
   7 *
   8 * Copyright (C) 1999  Niibe Yutaka & Takeshi Yaegashi
   9 * Copyright (C) 2000  Kazumoto Kojima
  10 * Copyright (C) 2001  David J. Mckay (david.mckay@st.com)
  11 * Copyright (C) 2003  Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp>
  12 * Copyright (C) 2005, 2006  Paul Mundt
  13 *
  14 * This file is subject to the terms and conditions of the GNU General Public
  15 * License.  See the file "COPYING" in the main directory of this archive
  16 * for more details.
  17 */
  18#include <linux/init.h>
  19#include <linux/irq.h>
  20#include <linux/module.h>
  21#include <linux/io.h>
  22#include <linux/interrupt.h>
  23#include <linux/bootmem.h>
  24#include <linux/sh_intc.h>
  25
  26#define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \
  27        ((shift) | ((width) << 5) | ((fn) << 9) | ((mode) << 13) | \
  28         ((addr_e) << 16) | ((addr_d << 24)))
  29
  30#define _INTC_SHIFT(h) (h & 0x1f)
  31#define _INTC_WIDTH(h) ((h >> 5) & 0xf)
  32#define _INTC_FN(h) ((h >> 9) & 0xf)
  33#define _INTC_MODE(h) ((h >> 13) & 0x7)
  34#define _INTC_ADDR_E(h) ((h >> 16) & 0xff)
  35#define _INTC_ADDR_D(h) ((h >> 24) & 0xff)
  36
  37struct intc_handle_int {
  38        unsigned int irq;
  39        unsigned long handle;
  40};
  41
  42struct intc_desc_int {
  43        unsigned long *reg;
  44#ifdef CONFIG_SMP
  45        unsigned long *smp;
  46#endif
  47        unsigned int nr_reg;
  48        struct intc_handle_int *prio;
  49        unsigned int nr_prio;
  50        struct intc_handle_int *sense;
  51        unsigned int nr_sense;
  52        struct irq_chip chip;
  53};
  54
  55#ifdef CONFIG_SMP
  56#define IS_SMP(x) x.smp
  57#define INTC_REG(d, x, c) (d->reg[(x)] + ((d->smp[(x)] & 0xff) * c))
  58#define SMP_NR(d, x) ((d->smp[(x)] >> 8) ? (d->smp[(x)] >> 8) : 1)
  59#else
  60#define IS_SMP(x) 0
  61#define INTC_REG(d, x, c) (d->reg[(x)])
  62#define SMP_NR(d, x) 1
  63#endif
  64
  65static unsigned int intc_prio_level[NR_IRQS]; /* for now */
  66#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A)
  67static unsigned long ack_handle[NR_IRQS];
  68#endif
  69
  70static inline struct intc_desc_int *get_intc_desc(unsigned int irq)
  71{
  72        struct irq_chip *chip = get_irq_chip(irq);
  73        return (void *)((char *)chip - offsetof(struct intc_desc_int, chip));
  74}
  75
  76static inline unsigned int set_field(unsigned int value,
  77                                     unsigned int field_value,
  78                                     unsigned int handle)
  79{
  80        unsigned int width = _INTC_WIDTH(handle);
  81        unsigned int shift = _INTC_SHIFT(handle);
  82
  83        value &= ~(((1 << width) - 1) << shift);
  84        value |= field_value << shift;
  85        return value;
  86}
  87
  88static void write_8(unsigned long addr, unsigned long h, unsigned long data)
  89{
  90        __raw_writeb(set_field(0, data, h), addr);
  91}
  92
  93static void write_16(unsigned long addr, unsigned long h, unsigned long data)
  94{
  95        __raw_writew(set_field(0, data, h), addr);
  96}
  97
  98static void write_32(unsigned long addr, unsigned long h, unsigned long data)
  99{
 100        __raw_writel(set_field(0, data, h), addr);
 101}
 102
 103static void modify_8(unsigned long addr, unsigned long h, unsigned long data)
 104{
 105        unsigned long flags;
 106        local_irq_save(flags);
 107        __raw_writeb(set_field(__raw_readb(addr), data, h), addr);
 108        local_irq_restore(flags);
 109}
 110
 111static void modify_16(unsigned long addr, unsigned long h, unsigned long data)
 112{
 113        unsigned long flags;
 114        local_irq_save(flags);
 115        __raw_writew(set_field(__raw_readw(addr), data, h), addr);
 116        local_irq_restore(flags);
 117}
 118
 119static void modify_32(unsigned long addr, unsigned long h, unsigned long data)
 120{
 121        unsigned long flags;
 122        local_irq_save(flags);
 123        __raw_writel(set_field(__raw_readl(addr), data, h), addr);
 124        local_irq_restore(flags);
 125}
 126
 127enum {  REG_FN_ERR = 0, REG_FN_WRITE_BASE = 1, REG_FN_MODIFY_BASE = 5 };
 128
 129static void (*intc_reg_fns[])(unsigned long addr,
 130                              unsigned long h,
 131                              unsigned long data) = {
 132        [REG_FN_WRITE_BASE + 0] = write_8,
 133        [REG_FN_WRITE_BASE + 1] = write_16,
 134        [REG_FN_WRITE_BASE + 3] = write_32,
 135        [REG_FN_MODIFY_BASE + 0] = modify_8,
 136        [REG_FN_MODIFY_BASE + 1] = modify_16,
 137        [REG_FN_MODIFY_BASE + 3] = modify_32,
 138};
 139
 140enum {  MODE_ENABLE_REG = 0, /* Bit(s) set -> interrupt enabled */
 141        MODE_MASK_REG,       /* Bit(s) set -> interrupt disabled */
 142        MODE_DUAL_REG,       /* Two registers, set bit to enable / disable */
 143        MODE_PRIO_REG,       /* Priority value written to enable interrupt */
 144        MODE_PCLR_REG,       /* Above plus all bits set to disable interrupt */
 145};
 146
 147static void intc_mode_field(unsigned long addr,
 148                            unsigned long handle,
 149                            void (*fn)(unsigned long,
 150                                       unsigned long,
 151                                       unsigned long),
 152                            unsigned int irq)
 153{
 154        fn(addr, handle, ((1 << _INTC_WIDTH(handle)) - 1));
 155}
 156
 157static void intc_mode_zero(unsigned long addr,
 158                           unsigned long handle,
 159                           void (*fn)(unsigned long,
 160                                       unsigned long,
 161                                       unsigned long),
 162                           unsigned int irq)
 163{
 164        fn(addr, handle, 0);
 165}
 166
 167static void intc_mode_prio(unsigned long addr,
 168                           unsigned long handle,
 169                           void (*fn)(unsigned long,
 170                                       unsigned long,
 171                                       unsigned long),
 172                           unsigned int irq)
 173{
 174        fn(addr, handle, intc_prio_level[irq]);
 175}
 176
 177static void (*intc_enable_fns[])(unsigned long addr,
 178                                 unsigned long handle,
 179                                 void (*fn)(unsigned long,
 180                                            unsigned long,
 181                                            unsigned long),
 182                                 unsigned int irq) = {
 183        [MODE_ENABLE_REG] = intc_mode_field,
 184        [MODE_MASK_REG] = intc_mode_zero,
 185        [MODE_DUAL_REG] = intc_mode_field,
 186        [MODE_PRIO_REG] = intc_mode_prio,
 187        [MODE_PCLR_REG] = intc_mode_prio,
 188};
 189
 190static void (*intc_disable_fns[])(unsigned long addr,
 191                                  unsigned long handle,
 192                                  void (*fn)(unsigned long,
 193                                             unsigned long,
 194                                             unsigned long),
 195                                  unsigned int irq) = {
 196        [MODE_ENABLE_REG] = intc_mode_zero,
 197        [MODE_MASK_REG] = intc_mode_field,
 198        [MODE_DUAL_REG] = intc_mode_field,
 199        [MODE_PRIO_REG] = intc_mode_zero,
 200        [MODE_PCLR_REG] = intc_mode_field,
 201};
 202
 203static inline void _intc_enable(unsigned int irq, unsigned long handle)
 204{
 205        struct intc_desc_int *d = get_intc_desc(irq);
 206        unsigned long addr;
 207        unsigned int cpu;
 208
 209        for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) {
 210                addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu);
 211                intc_enable_fns[_INTC_MODE(handle)](addr, handle, intc_reg_fns\
 212                                                    [_INTC_FN(handle)], irq);
 213        }
 214}
 215
 216static void intc_enable(unsigned int irq)
 217{
 218        _intc_enable(irq, (unsigned long)get_irq_chip_data(irq));
 219}
 220
 221static void intc_disable(unsigned int irq)
 222{
 223        struct intc_desc_int *d = get_intc_desc(irq);
 224        unsigned long handle = (unsigned long) get_irq_chip_data(irq);
 225        unsigned long addr;
 226        unsigned int cpu;
 227
 228        for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) {
 229                addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu);
 230                intc_disable_fns[_INTC_MODE(handle)](addr, handle,intc_reg_fns\
 231                                                     [_INTC_FN(handle)], irq);
 232        }
 233}
 234
 235#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A)
 236static void intc_mask_ack(unsigned int irq)
 237{
 238        struct intc_desc_int *d = get_intc_desc(irq);
 239        unsigned long handle = ack_handle[irq];
 240        unsigned long addr;
 241
 242        intc_disable(irq);
 243
 244        /* read register and write zero only to the assocaited bit */
 245
 246        if (handle) {
 247                addr = INTC_REG(d, _INTC_ADDR_D(handle), 0);
 248                switch (_INTC_FN(handle)) {
 249                case REG_FN_MODIFY_BASE + 0:    /* 8bit */
 250                        __raw_readb(addr);
 251                        __raw_writeb(0xff ^ set_field(0, 1, handle), addr);
 252                        break;
 253                case REG_FN_MODIFY_BASE + 1:    /* 16bit */
 254                        __raw_readw(addr);
 255                        __raw_writew(0xffff ^ set_field(0, 1, handle), addr);
 256                        break;
 257                case REG_FN_MODIFY_BASE + 3:    /* 32bit */
 258                        __raw_readl(addr);
 259                        __raw_writel(0xffffffff ^ set_field(0, 1, handle), addr);
 260                        break;
 261                default:
 262                        BUG();
 263                        break;
 264                }
 265        }
 266}
 267#endif
 268
 269static struct intc_handle_int *intc_find_irq(struct intc_handle_int *hp,
 270                                             unsigned int nr_hp,
 271                                             unsigned int irq)
 272{
 273        int i;
 274
 275        /* this doesn't scale well, but...
 276         *
 277         * this function should only be used for cerain uncommon
 278         * operations such as intc_set_priority() and intc_set_sense()
 279         * and in those rare cases performance doesn't matter that much.
 280         * keeping the memory footprint low is more important.
 281         *
 282         * one rather simple way to speed this up and still keep the
 283         * memory footprint down is to make sure the array is sorted
 284         * and then perform a bisect to lookup the irq.
 285         */
 286
 287        for (i = 0; i < nr_hp; i++) {
 288                if ((hp + i)->irq != irq)
 289                        continue;
 290
 291                return hp + i;
 292        }
 293
 294        return NULL;
 295}
 296
 297int intc_set_priority(unsigned int irq, unsigned int prio)
 298{
 299        struct intc_desc_int *d = get_intc_desc(irq);
 300        struct intc_handle_int *ihp;
 301
 302        if (!intc_prio_level[irq] || prio <= 1)
 303                return -EINVAL;
 304
 305        ihp = intc_find_irq(d->prio, d->nr_prio, irq);
 306        if (ihp) {
 307                if (prio >= (1 << _INTC_WIDTH(ihp->handle)))
 308                        return -EINVAL;
 309
 310                intc_prio_level[irq] = prio;
 311
 312                /*
 313                 * only set secondary masking method directly
 314                 * primary masking method is using intc_prio_level[irq]
 315                 * priority level will be set during next enable()
 316                 */
 317
 318                if (_INTC_FN(ihp->handle) != REG_FN_ERR)
 319                        _intc_enable(irq, ihp->handle);
 320        }
 321        return 0;
 322}
 323
 324#define VALID(x) (x | 0x80)
 325
 326static unsigned char intc_irq_sense_table[IRQ_TYPE_SENSE_MASK + 1] = {
 327        [IRQ_TYPE_EDGE_FALLING] = VALID(0),
 328        [IRQ_TYPE_EDGE_RISING] = VALID(1),
 329        [IRQ_TYPE_LEVEL_LOW] = VALID(2),
 330        /* SH7706, SH7707 and SH7709 do not support high level triggered */
 331#if !defined(CONFIG_CPU_SUBTYPE_SH7706) && \
 332    !defined(CONFIG_CPU_SUBTYPE_SH7707) && \
 333    !defined(CONFIG_CPU_SUBTYPE_SH7709)
 334        [IRQ_TYPE_LEVEL_HIGH] = VALID(3),
 335#endif
 336};
 337
 338static int intc_set_sense(unsigned int irq, unsigned int type)
 339{
 340        struct intc_desc_int *d = get_intc_desc(irq);
 341        unsigned char value = intc_irq_sense_table[type & IRQ_TYPE_SENSE_MASK];
 342        struct intc_handle_int *ihp;
 343        unsigned long addr;
 344
 345        if (!value)
 346                return -EINVAL;
 347
 348        ihp = intc_find_irq(d->sense, d->nr_sense, irq);
 349        if (ihp) {
 350                addr = INTC_REG(d, _INTC_ADDR_E(ihp->handle), 0);
 351                intc_reg_fns[_INTC_FN(ihp->handle)](addr, ihp->handle, value);
 352        }
 353        return 0;
 354}
 355
 356static unsigned int __init intc_get_reg(struct intc_desc_int *d,
 357                                 unsigned long address)
 358{
 359        unsigned int k;
 360
 361        for (k = 0; k < d->nr_reg; k++) {
 362                if (d->reg[k] == address)
 363                        return k;
 364        }
 365
 366        BUG();
 367        return 0;
 368}
 369
 370static intc_enum __init intc_grp_id(struct intc_desc *desc,
 371                                    intc_enum enum_id)
 372{
 373        struct intc_group *g = desc->groups;
 374        unsigned int i, j;
 375
 376        for (i = 0; g && enum_id && i < desc->nr_groups; i++) {
 377                g = desc->groups + i;
 378
 379                for (j = 0; g->enum_ids[j]; j++) {
 380                        if (g->enum_ids[j] != enum_id)
 381                                continue;
 382
 383                        return g->enum_id;
 384                }
 385        }
 386
 387        return 0;
 388}
 389
 390static unsigned int __init intc_mask_data(struct intc_desc *desc,
 391                                          struct intc_desc_int *d,
 392                                          intc_enum enum_id, int do_grps)
 393{
 394        struct intc_mask_reg *mr = desc->mask_regs;
 395        unsigned int i, j, fn, mode;
 396        unsigned long reg_e, reg_d;
 397
 398        for (i = 0; mr && enum_id && i < desc->nr_mask_regs; i++) {
 399                mr = desc->mask_regs + i;
 400
 401                for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) {
 402                        if (mr->enum_ids[j] != enum_id)
 403                                continue;
 404
 405                        if (mr->set_reg && mr->clr_reg) {
 406                                fn = REG_FN_WRITE_BASE;
 407                                mode = MODE_DUAL_REG;
 408                                reg_e = mr->clr_reg;
 409                                reg_d = mr->set_reg;
 410                        } else {
 411                                fn = REG_FN_MODIFY_BASE;
 412                                if (mr->set_reg) {
 413                                        mode = MODE_ENABLE_REG;
 414                                        reg_e = mr->set_reg;
 415                                        reg_d = mr->set_reg;
 416                                } else {
 417                                        mode = MODE_MASK_REG;
 418                                        reg_e = mr->clr_reg;
 419                                        reg_d = mr->clr_reg;
 420                                }
 421                        }
 422
 423                        fn += (mr->reg_width >> 3) - 1;
 424                        return _INTC_MK(fn, mode,
 425                                        intc_get_reg(d, reg_e),
 426                                        intc_get_reg(d, reg_d),
 427                                        1,
 428                                        (mr->reg_width - 1) - j);
 429                }
 430        }
 431
 432        if (do_grps)
 433                return intc_mask_data(desc, d, intc_grp_id(desc, enum_id), 0);
 434
 435        return 0;
 436}
 437
 438static unsigned int __init intc_prio_data(struct intc_desc *desc,
 439                                          struct intc_desc_int *d,
 440                                          intc_enum enum_id, int do_grps)
 441{
 442        struct intc_prio_reg *pr = desc->prio_regs;
 443        unsigned int i, j, fn, mode, bit;
 444        unsigned long reg_e, reg_d;
 445
 446        for (i = 0; pr && enum_id && i < desc->nr_prio_regs; i++) {
 447                pr = desc->prio_regs + i;
 448
 449                for (j = 0; j < ARRAY_SIZE(pr->enum_ids); j++) {
 450                        if (pr->enum_ids[j] != enum_id)
 451                                continue;
 452
 453                        if (pr->set_reg && pr->clr_reg) {
 454                                fn = REG_FN_WRITE_BASE;
 455                                mode = MODE_PCLR_REG;
 456                                reg_e = pr->set_reg;
 457                                reg_d = pr->clr_reg;
 458                        } else {
 459                                fn = REG_FN_MODIFY_BASE;
 460                                mode = MODE_PRIO_REG;
 461                                if (!pr->set_reg)
 462                                        BUG();
 463                                reg_e = pr->set_reg;
 464                                reg_d = pr->set_reg;
 465                        }
 466
 467                        fn += (pr->reg_width >> 3) - 1;
 468
 469                        BUG_ON((j + 1) * pr->field_width > pr->reg_width);
 470
 471                        bit = pr->reg_width - ((j + 1) * pr->field_width);
 472
 473                        return _INTC_MK(fn, mode,
 474                                        intc_get_reg(d, reg_e),
 475                                        intc_get_reg(d, reg_d),
 476                                        pr->field_width, bit);
 477                }
 478        }
 479
 480        if (do_grps)
 481                return intc_prio_data(desc, d, intc_grp_id(desc, enum_id), 0);
 482
 483        return 0;
 484}
 485
 486#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A)
 487static unsigned int __init intc_ack_data(struct intc_desc *desc,
 488                                          struct intc_desc_int *d,
 489                                          intc_enum enum_id)
 490{
 491        struct intc_mask_reg *mr = desc->ack_regs;
 492        unsigned int i, j, fn, mode;
 493        unsigned long reg_e, reg_d;
 494
 495        for (i = 0; mr && enum_id && i < desc->nr_ack_regs; i++) {
 496                mr = desc->ack_regs + i;
 497
 498                for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) {
 499                        if (mr->enum_ids[j] != enum_id)
 500                                continue;
 501
 502                        fn = REG_FN_MODIFY_BASE;
 503                        mode = MODE_ENABLE_REG;
 504                        reg_e = mr->set_reg;
 505                        reg_d = mr->set_reg;
 506
 507                        fn += (mr->reg_width >> 3) - 1;
 508                        return _INTC_MK(fn, mode,
 509                                        intc_get_reg(d, reg_e),
 510                                        intc_get_reg(d, reg_d),
 511                                        1,
 512                                        (mr->reg_width - 1) - j);
 513                }
 514        }
 515
 516        return 0;
 517}
 518#endif
 519
 520static unsigned int __init intc_sense_data(struct intc_desc *desc,
 521                                           struct intc_desc_int *d,
 522                                           intc_enum enum_id)
 523{
 524        struct intc_sense_reg *sr = desc->sense_regs;
 525        unsigned int i, j, fn, bit;
 526
 527        for (i = 0; sr && enum_id && i < desc->nr_sense_regs; i++) {
 528                sr = desc->sense_regs + i;
 529
 530                for (j = 0; j < ARRAY_SIZE(sr->enum_ids); j++) {
 531                        if (sr->enum_ids[j] != enum_id)
 532                                continue;
 533
 534                        fn = REG_FN_MODIFY_BASE;
 535                        fn += (sr->reg_width >> 3) - 1;
 536
 537                        BUG_ON((j + 1) * sr->field_width > sr->reg_width);
 538
 539                        bit = sr->reg_width - ((j + 1) * sr->field_width);
 540
 541                        return _INTC_MK(fn, 0, intc_get_reg(d, sr->reg),
 542                                        0, sr->field_width, bit);
 543                }
 544        }
 545
 546        return 0;
 547}
 548
 549static void __init intc_register_irq(struct intc_desc *desc,
 550                                     struct intc_desc_int *d,
 551                                     intc_enum enum_id,
 552                                     unsigned int irq)
 553{
 554        struct intc_handle_int *hp;
 555        unsigned int data[2], primary;
 556
 557        /* Prefer single interrupt source bitmap over other combinations:
 558         * 1. bitmap, single interrupt source
 559         * 2. priority, single interrupt source
 560         * 3. bitmap, multiple interrupt sources (groups)
 561         * 4. priority, multiple interrupt sources (groups)
 562         */
 563
 564        data[0] = intc_mask_data(desc, d, enum_id, 0);
 565        data[1] = intc_prio_data(desc, d, enum_id, 0);
 566
 567        primary = 0;
 568        if (!data[0] && data[1])
 569                primary = 1;
 570
 571        data[0] = data[0] ? data[0] : intc_mask_data(desc, d, enum_id, 1);
 572        data[1] = data[1] ? data[1] : intc_prio_data(desc, d, enum_id, 1);
 573
 574        if (!data[primary])
 575                primary ^= 1;
 576
 577        BUG_ON(!data[primary]); /* must have primary masking method */
 578
 579        disable_irq_nosync(irq);
 580        set_irq_chip_and_handler_name(irq, &d->chip,
 581                                      handle_level_irq, "level");
 582        set_irq_chip_data(irq, (void *)data[primary]);
 583
 584        /* set priority level
 585         * - this needs to be at least 2 for 5-bit priorities on 7780
 586         */
 587        intc_prio_level[irq] = 2;
 588
 589        /* enable secondary masking method if present */
 590        if (data[!primary])
 591                _intc_enable(irq, data[!primary]);
 592
 593        /* add irq to d->prio list if priority is available */
 594        if (data[1]) {
 595                hp = d->prio + d->nr_prio;
 596                hp->irq = irq;
 597                hp->handle = data[1];
 598
 599                if (primary) {
 600                        /*
 601                         * only secondary priority should access registers, so
 602                         * set _INTC_FN(h) = REG_FN_ERR for intc_set_priority()
 603                         */
 604
 605                        hp->handle &= ~_INTC_MK(0x0f, 0, 0, 0, 0, 0);
 606                        hp->handle |= _INTC_MK(REG_FN_ERR, 0, 0, 0, 0, 0);
 607                }
 608                d->nr_prio++;
 609        }
 610
 611        /* add irq to d->sense list if sense is available */
 612        data[0] = intc_sense_data(desc, d, enum_id);
 613        if (data[0]) {
 614                (d->sense + d->nr_sense)->irq = irq;
 615                (d->sense + d->nr_sense)->handle = data[0];
 616                d->nr_sense++;
 617        }
 618
 619        /* irq should be disabled by default */
 620        d->chip.mask(irq);
 621
 622#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A)
 623        if (desc->ack_regs)
 624                ack_handle[irq] = intc_ack_data(desc, d, enum_id);
 625#endif
 626}
 627
 628static unsigned int __init save_reg(struct intc_desc_int *d,
 629                                    unsigned int cnt,
 630                                    unsigned long value,
 631                                    unsigned int smp)
 632{
 633        if (value) {
 634                d->reg[cnt] = value;
 635#ifdef CONFIG_SMP
 636                d->smp[cnt] = smp;
 637#endif
 638                return 1;
 639        }
 640
 641        return 0;
 642}
 643
 644
 645void __init register_intc_controller(struct intc_desc *desc)
 646{
 647        unsigned int i, k, smp;
 648        struct intc_desc_int *d;
 649
 650        d = alloc_bootmem(sizeof(*d));
 651
 652        d->nr_reg = desc->mask_regs ? desc->nr_mask_regs * 2 : 0;
 653        d->nr_reg += desc->prio_regs ? desc->nr_prio_regs * 2 : 0;
 654        d->nr_reg += desc->sense_regs ? desc->nr_sense_regs : 0;
 655
 656#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A)
 657        d->nr_reg += desc->ack_regs ? desc->nr_ack_regs : 0;
 658#endif
 659        d->reg = alloc_bootmem(d->nr_reg * sizeof(*d->reg));
 660#ifdef CONFIG_SMP
 661        d->smp = alloc_bootmem(d->nr_reg * sizeof(*d->smp));
 662#endif
 663        k = 0;
 664
 665        if (desc->mask_regs) {
 666                for (i = 0; i < desc->nr_mask_regs; i++) {
 667                        smp = IS_SMP(desc->mask_regs[i]);
 668                        k += save_reg(d, k, desc->mask_regs[i].set_reg, smp);
 669                        k += save_reg(d, k, desc->mask_regs[i].clr_reg, smp);
 670                }
 671        }
 672
 673        if (desc->prio_regs) {
 674                d->prio = alloc_bootmem(desc->nr_vectors * sizeof(*d->prio));
 675
 676                for (i = 0; i < desc->nr_prio_regs; i++) {
 677                        smp = IS_SMP(desc->prio_regs[i]);
 678                        k += save_reg(d, k, desc->prio_regs[i].set_reg, smp);
 679                        k += save_reg(d, k, desc->prio_regs[i].clr_reg, smp);
 680                }
 681        }
 682
 683        if (desc->sense_regs) {
 684                d->sense = alloc_bootmem(desc->nr_vectors * sizeof(*d->sense));
 685
 686                for (i = 0; i < desc->nr_sense_regs; i++) {
 687                        k += save_reg(d, k, desc->sense_regs[i].reg, 0);
 688                }
 689        }
 690
 691        d->chip.name = desc->name;
 692        d->chip.mask = intc_disable;
 693        d->chip.unmask = intc_enable;
 694        d->chip.mask_ack = intc_disable;
 695        d->chip.set_type = intc_set_sense;
 696
 697#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A)
 698        if (desc->ack_regs) {
 699                for (i = 0; i < desc->nr_ack_regs; i++)
 700                        k += save_reg(d, k, desc->ack_regs[i].set_reg, 0);
 701
 702                d->chip.mask_ack = intc_mask_ack;
 703        }
 704#endif
 705
 706        BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */
 707
 708        for (i = 0; i < desc->nr_vectors; i++) {
 709                struct intc_vect *vect = desc->vectors + i;
 710
 711                intc_register_irq(desc, d, vect->enum_id, evt2irq(vect->vect));
 712        }
 713}
 714