linux/arch/sparc/kernel/prom_irqtrans.c
<<
>>
Prefs
   1#include <linux/kernel.h>
   2#include <linux/string.h>
   3#include <linux/init.h>
   4#include <linux/of.h>
   5#include <linux/of_platform.h>
   6
   7#include <asm/oplib.h>
   8#include <asm/prom.h>
   9#include <asm/irq.h>
  10#include <asm/upa.h>
  11
  12#include "prom.h"
  13
  14#ifdef CONFIG_PCI
  15/* PSYCHO interrupt mapping support. */
  16#define PSYCHO_IMAP_A_SLOT0     0x0c00UL
  17#define PSYCHO_IMAP_B_SLOT0     0x0c20UL
  18static unsigned long psycho_pcislot_imap_offset(unsigned long ino)
  19{
  20        unsigned int bus =  (ino & 0x10) >> 4;
  21        unsigned int slot = (ino & 0x0c) >> 2;
  22
  23        if (bus == 0)
  24                return PSYCHO_IMAP_A_SLOT0 + (slot * 8);
  25        else
  26                return PSYCHO_IMAP_B_SLOT0 + (slot * 8);
  27}
  28
  29#define PSYCHO_OBIO_IMAP_BASE   0x1000UL
  30
  31#define PSYCHO_ONBOARD_IRQ_BASE         0x20
  32#define psycho_onboard_imap_offset(__ino) \
  33        (PSYCHO_OBIO_IMAP_BASE + (((__ino) & 0x1f) << 3))
  34
  35#define PSYCHO_ICLR_A_SLOT0     0x1400UL
  36#define PSYCHO_ICLR_SCSI        0x1800UL
  37
  38#define psycho_iclr_offset(ino)                                       \
  39        ((ino & 0x20) ? (PSYCHO_ICLR_SCSI + (((ino) & 0x1f) << 3)) :  \
  40                        (PSYCHO_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3)))
  41
  42static unsigned int psycho_irq_build(struct device_node *dp,
  43                                     unsigned int ino,
  44                                     void *_data)
  45{
  46        unsigned long controller_regs = (unsigned long) _data;
  47        unsigned long imap, iclr;
  48        unsigned long imap_off, iclr_off;
  49        int inofixup = 0;
  50
  51        ino &= 0x3f;
  52        if (ino < PSYCHO_ONBOARD_IRQ_BASE) {
  53                /* PCI slot */
  54                imap_off = psycho_pcislot_imap_offset(ino);
  55        } else {
  56                /* Onboard device */
  57                imap_off = psycho_onboard_imap_offset(ino);
  58        }
  59
  60        /* Now build the IRQ bucket. */
  61        imap = controller_regs + imap_off;
  62
  63        iclr_off = psycho_iclr_offset(ino);
  64        iclr = controller_regs + iclr_off;
  65
  66        if ((ino & 0x20) == 0)
  67                inofixup = ino & 0x03;
  68
  69        return build_irq(inofixup, iclr, imap);
  70}
  71
  72static void __init psycho_irq_trans_init(struct device_node *dp)
  73{
  74        const struct linux_prom64_registers *regs;
  75
  76        dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
  77        dp->irq_trans->irq_build = psycho_irq_build;
  78
  79        regs = of_get_property(dp, "reg", NULL);
  80        dp->irq_trans->data = (void *) regs[2].phys_addr;
  81}
  82
  83#define sabre_read(__reg) \
  84({      u64 __ret; \
  85        __asm__ __volatile__("ldxa [%1] %2, %0" \
  86                             : "=r" (__ret) \
  87                             : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \
  88                             : "memory"); \
  89        __ret; \
  90})
  91
  92struct sabre_irq_data {
  93        unsigned long controller_regs;
  94        unsigned int pci_first_busno;
  95};
  96#define SABRE_CONFIGSPACE       0x001000000UL
  97#define SABRE_WRSYNC            0x1c20UL
  98
  99#define SABRE_CONFIG_BASE(CONFIG_SPACE) \
 100        (CONFIG_SPACE | (1UL << 24))
 101#define SABRE_CONFIG_ENCODE(BUS, DEVFN, REG)    \
 102        (((unsigned long)(BUS)   << 16) |       \
 103         ((unsigned long)(DEVFN) << 8)  |       \
 104         ((unsigned long)(REG)))
 105
 106/* When a device lives behind a bridge deeper in the PCI bus topology
 107 * than APB, a special sequence must run to make sure all pending DMA
 108 * transfers at the time of IRQ delivery are visible in the coherency
 109 * domain by the cpu.  This sequence is to perform a read on the far
 110 * side of the non-APB bridge, then perform a read of Sabre's DMA
 111 * write-sync register.
 112 */
 113static void sabre_wsync_handler(unsigned int ino, void *_arg1, void *_arg2)
 114{
 115        unsigned int phys_hi = (unsigned int) (unsigned long) _arg1;
 116        struct sabre_irq_data *irq_data = _arg2;
 117        unsigned long controller_regs = irq_data->controller_regs;
 118        unsigned long sync_reg = controller_regs + SABRE_WRSYNC;
 119        unsigned long config_space = controller_regs + SABRE_CONFIGSPACE;
 120        unsigned int bus, devfn;
 121        u16 _unused;
 122
 123        config_space = SABRE_CONFIG_BASE(config_space);
 124
 125        bus = (phys_hi >> 16) & 0xff;
 126        devfn = (phys_hi >> 8) & 0xff;
 127
 128        config_space |= SABRE_CONFIG_ENCODE(bus, devfn, 0x00);
 129
 130        __asm__ __volatile__("membar #Sync\n\t"
 131                             "lduha [%1] %2, %0\n\t"
 132                             "membar #Sync"
 133                             : "=r" (_unused)
 134                             : "r" ((u16 *) config_space),
 135                               "i" (ASI_PHYS_BYPASS_EC_E_L)
 136                             : "memory");
 137
 138        sabre_read(sync_reg);
 139}
 140
 141#define SABRE_IMAP_A_SLOT0      0x0c00UL
 142#define SABRE_IMAP_B_SLOT0      0x0c20UL
 143#define SABRE_ICLR_A_SLOT0      0x1400UL
 144#define SABRE_ICLR_B_SLOT0      0x1480UL
 145#define SABRE_ICLR_SCSI         0x1800UL
 146#define SABRE_ICLR_ETH          0x1808UL
 147#define SABRE_ICLR_BPP          0x1810UL
 148#define SABRE_ICLR_AU_REC       0x1818UL
 149#define SABRE_ICLR_AU_PLAY      0x1820UL
 150#define SABRE_ICLR_PFAIL        0x1828UL
 151#define SABRE_ICLR_KMS          0x1830UL
 152#define SABRE_ICLR_FLPY         0x1838UL
 153#define SABRE_ICLR_SHW          0x1840UL
 154#define SABRE_ICLR_KBD          0x1848UL
 155#define SABRE_ICLR_MS           0x1850UL
 156#define SABRE_ICLR_SER          0x1858UL
 157#define SABRE_ICLR_UE           0x1870UL
 158#define SABRE_ICLR_CE           0x1878UL
 159#define SABRE_ICLR_PCIERR       0x1880UL
 160
 161static unsigned long sabre_pcislot_imap_offset(unsigned long ino)
 162{
 163        unsigned int bus =  (ino & 0x10) >> 4;
 164        unsigned int slot = (ino & 0x0c) >> 2;
 165
 166        if (bus == 0)
 167                return SABRE_IMAP_A_SLOT0 + (slot * 8);
 168        else
 169                return SABRE_IMAP_B_SLOT0 + (slot * 8);
 170}
 171
 172#define SABRE_OBIO_IMAP_BASE    0x1000UL
 173#define SABRE_ONBOARD_IRQ_BASE  0x20
 174#define sabre_onboard_imap_offset(__ino) \
 175        (SABRE_OBIO_IMAP_BASE + (((__ino) & 0x1f) << 3))
 176
 177#define sabre_iclr_offset(ino)                                        \
 178        ((ino & 0x20) ? (SABRE_ICLR_SCSI + (((ino) & 0x1f) << 3)) :  \
 179                        (SABRE_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3)))
 180
 181static int sabre_device_needs_wsync(struct device_node *dp)
 182{
 183        struct device_node *parent = dp->parent;
 184        const char *parent_model, *parent_compat;
 185
 186        /* This traversal up towards the root is meant to
 187         * handle two cases:
 188         *
 189         * 1) non-PCI bus sitting under PCI, such as 'ebus'
 190         * 2) the PCI controller interrupts themselves, which
 191         *    will use the sabre_irq_build but do not need
 192         *    the DMA synchronization handling
 193         */
 194        while (parent) {
 195                if (!strcmp(parent->type, "pci"))
 196                        break;
 197                parent = parent->parent;
 198        }
 199
 200        if (!parent)
 201                return 0;
 202
 203        parent_model = of_get_property(parent,
 204                                       "model", NULL);
 205        if (parent_model &&
 206            (!strcmp(parent_model, "SUNW,sabre") ||
 207             !strcmp(parent_model, "SUNW,simba")))
 208                return 0;
 209
 210        parent_compat = of_get_property(parent,
 211                                        "compatible", NULL);
 212        if (parent_compat &&
 213            (!strcmp(parent_compat, "pci108e,a000") ||
 214             !strcmp(parent_compat, "pci108e,a001")))
 215                return 0;
 216
 217        return 1;
 218}
 219
 220static unsigned int sabre_irq_build(struct device_node *dp,
 221                                    unsigned int ino,
 222                                    void *_data)
 223{
 224        struct sabre_irq_data *irq_data = _data;
 225        unsigned long controller_regs = irq_data->controller_regs;
 226        const struct linux_prom_pci_registers *regs;
 227        unsigned long imap, iclr;
 228        unsigned long imap_off, iclr_off;
 229        int inofixup = 0;
 230        int irq;
 231
 232        ino &= 0x3f;
 233        if (ino < SABRE_ONBOARD_IRQ_BASE) {
 234                /* PCI slot */
 235                imap_off = sabre_pcislot_imap_offset(ino);
 236        } else {
 237                /* onboard device */
 238                imap_off = sabre_onboard_imap_offset(ino);
 239        }
 240
 241        /* Now build the IRQ bucket. */
 242        imap = controller_regs + imap_off;
 243
 244        iclr_off = sabre_iclr_offset(ino);
 245        iclr = controller_regs + iclr_off;
 246
 247        if ((ino & 0x20) == 0)
 248                inofixup = ino & 0x03;
 249
 250        irq = build_irq(inofixup, iclr, imap);
 251
 252        /* If the parent device is a PCI<->PCI bridge other than
 253         * APB, we have to install a pre-handler to ensure that
 254         * all pending DMA is drained before the interrupt handler
 255         * is run.
 256         */
 257        regs = of_get_property(dp, "reg", NULL);
 258        if (regs && sabre_device_needs_wsync(dp)) {
 259                irq_install_pre_handler(irq,
 260                                        sabre_wsync_handler,
 261                                        (void *) (long) regs->phys_hi,
 262                                        (void *) irq_data);
 263        }
 264
 265        return irq;
 266}
 267
 268static void __init sabre_irq_trans_init(struct device_node *dp)
 269{
 270        const struct linux_prom64_registers *regs;
 271        struct sabre_irq_data *irq_data;
 272        const u32 *busrange;
 273
 274        dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
 275        dp->irq_trans->irq_build = sabre_irq_build;
 276
 277        irq_data = prom_early_alloc(sizeof(struct sabre_irq_data));
 278
 279        regs = of_get_property(dp, "reg", NULL);
 280        irq_data->controller_regs = regs[0].phys_addr;
 281
 282        busrange = of_get_property(dp, "bus-range", NULL);
 283        irq_data->pci_first_busno = busrange[0];
 284
 285        dp->irq_trans->data = irq_data;
 286}
 287
 288/* SCHIZO interrupt mapping support.  Unlike Psycho, for this controller the
 289 * imap/iclr registers are per-PBM.
 290 */
 291#define SCHIZO_IMAP_BASE        0x1000UL
 292#define SCHIZO_ICLR_BASE        0x1400UL
 293
 294static unsigned long schizo_imap_offset(unsigned long ino)
 295{
 296        return SCHIZO_IMAP_BASE + (ino * 8UL);
 297}
 298
 299static unsigned long schizo_iclr_offset(unsigned long ino)
 300{
 301        return SCHIZO_ICLR_BASE + (ino * 8UL);
 302}
 303
 304static unsigned long schizo_ino_to_iclr(unsigned long pbm_regs,
 305                                        unsigned int ino)
 306{
 307
 308        return pbm_regs + schizo_iclr_offset(ino);
 309}
 310
 311static unsigned long schizo_ino_to_imap(unsigned long pbm_regs,
 312                                        unsigned int ino)
 313{
 314        return pbm_regs + schizo_imap_offset(ino);
 315}
 316
 317#define schizo_read(__reg) \
 318({      u64 __ret; \
 319        __asm__ __volatile__("ldxa [%1] %2, %0" \
 320                             : "=r" (__ret) \
 321                             : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \
 322                             : "memory"); \
 323        __ret; \
 324})
 325#define schizo_write(__reg, __val) \
 326        __asm__ __volatile__("stxa %0, [%1] %2" \
 327                             : /* no outputs */ \
 328                             : "r" (__val), "r" (__reg), \
 329                               "i" (ASI_PHYS_BYPASS_EC_E) \
 330                             : "memory")
 331
 332static void tomatillo_wsync_handler(unsigned int ino, void *_arg1, void *_arg2)
 333{
 334        unsigned long sync_reg = (unsigned long) _arg2;
 335        u64 mask = 1UL << (ino & IMAP_INO);
 336        u64 val;
 337        int limit;
 338
 339        schizo_write(sync_reg, mask);
 340
 341        limit = 100000;
 342        val = 0;
 343        while (--limit) {
 344                val = schizo_read(sync_reg);
 345                if (!(val & mask))
 346                        break;
 347        }
 348        if (limit <= 0) {
 349                printk("tomatillo_wsync_handler: DMA won't sync [%llx:%llx]\n",
 350                       val, mask);
 351        }
 352
 353        if (_arg1) {
 354                static unsigned char cacheline[64]
 355                        __attribute__ ((aligned (64)));
 356
 357                __asm__ __volatile__("rd %%fprs, %0\n\t"
 358                                     "or %0, %4, %1\n\t"
 359                                     "wr %1, 0x0, %%fprs\n\t"
 360                                     "stda %%f0, [%5] %6\n\t"
 361                                     "wr %0, 0x0, %%fprs\n\t"
 362                                     "membar #Sync"
 363                                     : "=&r" (mask), "=&r" (val)
 364                                     : "0" (mask), "1" (val),
 365                                     "i" (FPRS_FEF), "r" (&cacheline[0]),
 366                                     "i" (ASI_BLK_COMMIT_P));
 367        }
 368}
 369
 370struct schizo_irq_data {
 371        unsigned long pbm_regs;
 372        unsigned long sync_reg;
 373        u32 portid;
 374        int chip_version;
 375};
 376
 377static unsigned int schizo_irq_build(struct device_node *dp,
 378                                     unsigned int ino,
 379                                     void *_data)
 380{
 381        struct schizo_irq_data *irq_data = _data;
 382        unsigned long pbm_regs = irq_data->pbm_regs;
 383        unsigned long imap, iclr;
 384        int ign_fixup;
 385        int irq;
 386        int is_tomatillo;
 387
 388        ino &= 0x3f;
 389
 390        /* Now build the IRQ bucket. */
 391        imap = schizo_ino_to_imap(pbm_regs, ino);
 392        iclr = schizo_ino_to_iclr(pbm_regs, ino);
 393
 394        /* On Schizo, no inofixup occurs.  This is because each
 395         * INO has it's own IMAP register.  On Psycho and Sabre
 396         * there is only one IMAP register for each PCI slot even
 397         * though four different INOs can be generated by each
 398         * PCI slot.
 399         *
 400         * But, for JBUS variants (essentially, Tomatillo), we have
 401         * to fixup the lowest bit of the interrupt group number.
 402         */
 403        ign_fixup = 0;
 404
 405        is_tomatillo = (irq_data->sync_reg != 0UL);
 406
 407        if (is_tomatillo) {
 408                if (irq_data->portid & 1)
 409                        ign_fixup = (1 << 6);
 410        }
 411
 412        irq = build_irq(ign_fixup, iclr, imap);
 413
 414        if (is_tomatillo) {
 415                irq_install_pre_handler(irq,
 416                                        tomatillo_wsync_handler,
 417                                        ((irq_data->chip_version <= 4) ?
 418                                         (void *) 1 : (void *) 0),
 419                                        (void *) irq_data->sync_reg);
 420        }
 421
 422        return irq;
 423}
 424
 425static void __init __schizo_irq_trans_init(struct device_node *dp,
 426                                           int is_tomatillo)
 427{
 428        const struct linux_prom64_registers *regs;
 429        struct schizo_irq_data *irq_data;
 430
 431        dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
 432        dp->irq_trans->irq_build = schizo_irq_build;
 433
 434        irq_data = prom_early_alloc(sizeof(struct schizo_irq_data));
 435
 436        regs = of_get_property(dp, "reg", NULL);
 437        dp->irq_trans->data = irq_data;
 438
 439        irq_data->pbm_regs = regs[0].phys_addr;
 440        if (is_tomatillo)
 441                irq_data->sync_reg = regs[3].phys_addr + 0x1a18UL;
 442        else
 443                irq_data->sync_reg = 0UL;
 444        irq_data->portid = of_getintprop_default(dp, "portid", 0);
 445        irq_data->chip_version = of_getintprop_default(dp, "version#", 0);
 446}
 447
 448static void __init schizo_irq_trans_init(struct device_node *dp)
 449{
 450        __schizo_irq_trans_init(dp, 0);
 451}
 452
 453static void __init tomatillo_irq_trans_init(struct device_node *dp)
 454{
 455        __schizo_irq_trans_init(dp, 1);
 456}
 457
 458static unsigned int pci_sun4v_irq_build(struct device_node *dp,
 459                                        unsigned int devino,
 460                                        void *_data)
 461{
 462        u32 devhandle = (u32) (unsigned long) _data;
 463
 464        return sun4v_build_irq(devhandle, devino);
 465}
 466
 467static void __init pci_sun4v_irq_trans_init(struct device_node *dp)
 468{
 469        const struct linux_prom64_registers *regs;
 470
 471        dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
 472        dp->irq_trans->irq_build = pci_sun4v_irq_build;
 473
 474        regs = of_get_property(dp, "reg", NULL);
 475        dp->irq_trans->data = (void *) (unsigned long)
 476                ((regs->phys_addr >> 32UL) & 0x0fffffff);
 477}
 478
 479struct fire_irq_data {
 480        unsigned long pbm_regs;
 481        u32 portid;
 482};
 483
 484#define FIRE_IMAP_BASE  0x001000
 485#define FIRE_ICLR_BASE  0x001400
 486
 487static unsigned long fire_imap_offset(unsigned long ino)
 488{
 489        return FIRE_IMAP_BASE + (ino * 8UL);
 490}
 491
 492static unsigned long fire_iclr_offset(unsigned long ino)
 493{
 494        return FIRE_ICLR_BASE + (ino * 8UL);
 495}
 496
 497static unsigned long fire_ino_to_iclr(unsigned long pbm_regs,
 498                                            unsigned int ino)
 499{
 500        return pbm_regs + fire_iclr_offset(ino);
 501}
 502
 503static unsigned long fire_ino_to_imap(unsigned long pbm_regs,
 504                                            unsigned int ino)
 505{
 506        return pbm_regs + fire_imap_offset(ino);
 507}
 508
 509static unsigned int fire_irq_build(struct device_node *dp,
 510                                         unsigned int ino,
 511                                         void *_data)
 512{
 513        struct fire_irq_data *irq_data = _data;
 514        unsigned long pbm_regs = irq_data->pbm_regs;
 515        unsigned long imap, iclr;
 516        unsigned long int_ctrlr;
 517
 518        ino &= 0x3f;
 519
 520        /* Now build the IRQ bucket. */
 521        imap = fire_ino_to_imap(pbm_regs, ino);
 522        iclr = fire_ino_to_iclr(pbm_regs, ino);
 523
 524        /* Set the interrupt controller number.  */
 525        int_ctrlr = 1 << 6;
 526        upa_writeq(int_ctrlr, imap);
 527
 528        /* The interrupt map registers do not have an INO field
 529         * like other chips do.  They return zero in the INO
 530         * field, and the interrupt controller number is controlled
 531         * in bits 6 to 9.  So in order for build_irq() to get
 532         * the INO right we pass it in as part of the fixup
 533         * which will get added to the map register zero value
 534         * read by build_irq().
 535         */
 536        ino |= (irq_data->portid << 6);
 537        ino -= int_ctrlr;
 538        return build_irq(ino, iclr, imap);
 539}
 540
 541static void __init fire_irq_trans_init(struct device_node *dp)
 542{
 543        const struct linux_prom64_registers *regs;
 544        struct fire_irq_data *irq_data;
 545
 546        dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
 547        dp->irq_trans->irq_build = fire_irq_build;
 548
 549        irq_data = prom_early_alloc(sizeof(struct fire_irq_data));
 550
 551        regs = of_get_property(dp, "reg", NULL);
 552        dp->irq_trans->data = irq_data;
 553
 554        irq_data->pbm_regs = regs[0].phys_addr;
 555        irq_data->portid = of_getintprop_default(dp, "portid", 0);
 556}
 557#endif /* CONFIG_PCI */
 558
 559#ifdef CONFIG_SBUS
 560/* INO number to IMAP register offset for SYSIO external IRQ's.
 561 * This should conform to both Sunfire/Wildfire server and Fusion
 562 * desktop designs.
 563 */
 564#define SYSIO_IMAP_SLOT0        0x2c00UL
 565#define SYSIO_IMAP_SLOT1        0x2c08UL
 566#define SYSIO_IMAP_SLOT2        0x2c10UL
 567#define SYSIO_IMAP_SLOT3        0x2c18UL
 568#define SYSIO_IMAP_SCSI         0x3000UL
 569#define SYSIO_IMAP_ETH          0x3008UL
 570#define SYSIO_IMAP_BPP          0x3010UL
 571#define SYSIO_IMAP_AUDIO        0x3018UL
 572#define SYSIO_IMAP_PFAIL        0x3020UL
 573#define SYSIO_IMAP_KMS          0x3028UL
 574#define SYSIO_IMAP_FLPY         0x3030UL
 575#define SYSIO_IMAP_SHW          0x3038UL
 576#define SYSIO_IMAP_KBD          0x3040UL
 577#define SYSIO_IMAP_MS           0x3048UL
 578#define SYSIO_IMAP_SER          0x3050UL
 579#define SYSIO_IMAP_TIM0         0x3060UL
 580#define SYSIO_IMAP_TIM1         0x3068UL
 581#define SYSIO_IMAP_UE           0x3070UL
 582#define SYSIO_IMAP_CE           0x3078UL
 583#define SYSIO_IMAP_SBERR        0x3080UL
 584#define SYSIO_IMAP_PMGMT        0x3088UL
 585#define SYSIO_IMAP_GFX          0x3090UL
 586#define SYSIO_IMAP_EUPA         0x3098UL
 587
 588#define bogon     ((unsigned long) -1)
 589static unsigned long sysio_irq_offsets[] = {
 590        /* SBUS Slot 0 --> 3, level 1 --> 7 */
 591        SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0,
 592        SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0,
 593        SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1,
 594        SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1,
 595        SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2,
 596        SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2,
 597        SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3,
 598        SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3,
 599
 600        /* Onboard devices (not relevant/used on SunFire). */
 601        SYSIO_IMAP_SCSI,
 602        SYSIO_IMAP_ETH,
 603        SYSIO_IMAP_BPP,
 604        bogon,
 605        SYSIO_IMAP_AUDIO,
 606        SYSIO_IMAP_PFAIL,
 607        bogon,
 608        bogon,
 609        SYSIO_IMAP_KMS,
 610        SYSIO_IMAP_FLPY,
 611        SYSIO_IMAP_SHW,
 612        SYSIO_IMAP_KBD,
 613        SYSIO_IMAP_MS,
 614        SYSIO_IMAP_SER,
 615        bogon,
 616        bogon,
 617        SYSIO_IMAP_TIM0,
 618        SYSIO_IMAP_TIM1,
 619        bogon,
 620        bogon,
 621        SYSIO_IMAP_UE,
 622        SYSIO_IMAP_CE,
 623        SYSIO_IMAP_SBERR,
 624        SYSIO_IMAP_PMGMT,
 625        SYSIO_IMAP_GFX,
 626        SYSIO_IMAP_EUPA,
 627};
 628
 629#undef bogon
 630
 631#define NUM_SYSIO_OFFSETS ARRAY_SIZE(sysio_irq_offsets)
 632
 633/* Convert Interrupt Mapping register pointer to associated
 634 * Interrupt Clear register pointer, SYSIO specific version.
 635 */
 636#define SYSIO_ICLR_UNUSED0      0x3400UL
 637#define SYSIO_ICLR_SLOT0        0x3408UL
 638#define SYSIO_ICLR_SLOT1        0x3448UL
 639#define SYSIO_ICLR_SLOT2        0x3488UL
 640#define SYSIO_ICLR_SLOT3        0x34c8UL
 641static unsigned long sysio_imap_to_iclr(unsigned long imap)
 642{
 643        unsigned long diff = SYSIO_ICLR_UNUSED0 - SYSIO_IMAP_SLOT0;
 644        return imap + diff;
 645}
 646
 647static unsigned int sbus_of_build_irq(struct device_node *dp,
 648                                      unsigned int ino,
 649                                      void *_data)
 650{
 651        unsigned long reg_base = (unsigned long) _data;
 652        const struct linux_prom_registers *regs;
 653        unsigned long imap, iclr;
 654        int sbus_slot = 0;
 655        int sbus_level = 0;
 656
 657        ino &= 0x3f;
 658
 659        regs = of_get_property(dp, "reg", NULL);
 660        if (regs)
 661                sbus_slot = regs->which_io;
 662
 663        if (ino < 0x20)
 664                ino += (sbus_slot * 8);
 665
 666        imap = sysio_irq_offsets[ino];
 667        if (imap == ((unsigned long)-1)) {
 668                prom_printf("get_irq_translations: Bad SYSIO INO[%x]\n",
 669                            ino);
 670                prom_halt();
 671        }
 672        imap += reg_base;
 673
 674        /* SYSIO inconsistency.  For external SLOTS, we have to select
 675         * the right ICLR register based upon the lower SBUS irq level
 676         * bits.
 677         */
 678        if (ino >= 0x20) {
 679                iclr = sysio_imap_to_iclr(imap);
 680        } else {
 681                sbus_level = ino & 0x7;
 682
 683                switch(sbus_slot) {
 684                case 0:
 685                        iclr = reg_base + SYSIO_ICLR_SLOT0;
 686                        break;
 687                case 1:
 688                        iclr = reg_base + SYSIO_ICLR_SLOT1;
 689                        break;
 690                case 2:
 691                        iclr = reg_base + SYSIO_ICLR_SLOT2;
 692                        break;
 693                default:
 694                case 3:
 695                        iclr = reg_base + SYSIO_ICLR_SLOT3;
 696                        break;
 697                }
 698
 699                iclr += ((unsigned long)sbus_level - 1UL) * 8UL;
 700        }
 701        return build_irq(sbus_level, iclr, imap);
 702}
 703
 704static void __init sbus_irq_trans_init(struct device_node *dp)
 705{
 706        const struct linux_prom64_registers *regs;
 707
 708        dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
 709        dp->irq_trans->irq_build = sbus_of_build_irq;
 710
 711        regs = of_get_property(dp, "reg", NULL);
 712        dp->irq_trans->data = (void *) (unsigned long) regs->phys_addr;
 713}
 714#endif /* CONFIG_SBUS */
 715
 716
 717static unsigned int central_build_irq(struct device_node *dp,
 718                                      unsigned int ino,
 719                                      void *_data)
 720{
 721        struct device_node *central_dp = _data;
 722        struct platform_device *central_op = of_find_device_by_node(central_dp);
 723        struct resource *res;
 724        unsigned long imap, iclr;
 725        u32 tmp;
 726
 727        if (!strcmp(dp->name, "eeprom")) {
 728                res = &central_op->resource[5];
 729        } else if (!strcmp(dp->name, "zs")) {
 730                res = &central_op->resource[4];
 731        } else if (!strcmp(dp->name, "clock-board")) {
 732                res = &central_op->resource[3];
 733        } else {
 734                return ino;
 735        }
 736
 737        imap = res->start + 0x00UL;
 738        iclr = res->start + 0x10UL;
 739
 740        /* Set the INO state to idle, and disable.  */
 741        upa_writel(0, iclr);
 742        upa_readl(iclr);
 743
 744        tmp = upa_readl(imap);
 745        tmp &= ~0x80000000;
 746        upa_writel(tmp, imap);
 747
 748        return build_irq(0, iclr, imap);
 749}
 750
 751static void __init central_irq_trans_init(struct device_node *dp)
 752{
 753        dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
 754        dp->irq_trans->irq_build = central_build_irq;
 755
 756        dp->irq_trans->data = dp;
 757}
 758
 759struct irq_trans {
 760        const char *name;
 761        void (*init)(struct device_node *);
 762};
 763
 764#ifdef CONFIG_PCI
 765static struct irq_trans __initdata pci_irq_trans_table[] = {
 766        { "SUNW,sabre", sabre_irq_trans_init },
 767        { "pci108e,a000", sabre_irq_trans_init },
 768        { "pci108e,a001", sabre_irq_trans_init },
 769        { "SUNW,psycho", psycho_irq_trans_init },
 770        { "pci108e,8000", psycho_irq_trans_init },
 771        { "SUNW,schizo", schizo_irq_trans_init },
 772        { "pci108e,8001", schizo_irq_trans_init },
 773        { "SUNW,schizo+", schizo_irq_trans_init },
 774        { "pci108e,8002", schizo_irq_trans_init },
 775        { "SUNW,tomatillo", tomatillo_irq_trans_init },
 776        { "pci108e,a801", tomatillo_irq_trans_init },
 777        { "SUNW,sun4v-pci", pci_sun4v_irq_trans_init },
 778        { "pciex108e,80f0", fire_irq_trans_init },
 779};
 780#endif
 781
 782static unsigned int sun4v_vdev_irq_build(struct device_node *dp,
 783                                         unsigned int devino,
 784                                         void *_data)
 785{
 786        u32 devhandle = (u32) (unsigned long) _data;
 787
 788        return sun4v_build_irq(devhandle, devino);
 789}
 790
 791static void __init sun4v_vdev_irq_trans_init(struct device_node *dp)
 792{
 793        const struct linux_prom64_registers *regs;
 794
 795        dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
 796        dp->irq_trans->irq_build = sun4v_vdev_irq_build;
 797
 798        regs = of_get_property(dp, "reg", NULL);
 799        dp->irq_trans->data = (void *) (unsigned long)
 800                ((regs->phys_addr >> 32UL) & 0x0fffffff);
 801}
 802
 803void __init irq_trans_init(struct device_node *dp)
 804{
 805#ifdef CONFIG_PCI
 806        const char *model;
 807        int i;
 808#endif
 809
 810#ifdef CONFIG_PCI
 811        model = of_get_property(dp, "model", NULL);
 812        if (!model)
 813                model = of_get_property(dp, "compatible", NULL);
 814        if (model) {
 815                for (i = 0; i < ARRAY_SIZE(pci_irq_trans_table); i++) {
 816                        struct irq_trans *t = &pci_irq_trans_table[i];
 817
 818                        if (!strcmp(model, t->name)) {
 819                                t->init(dp);
 820                                return;
 821                        }
 822                }
 823        }
 824#endif
 825#ifdef CONFIG_SBUS
 826        if (!strcmp(dp->name, "sbus") ||
 827            !strcmp(dp->name, "sbi")) {
 828                sbus_irq_trans_init(dp);
 829                return;
 830        }
 831#endif
 832        if (!strcmp(dp->name, "fhc") &&
 833            !strcmp(dp->parent->name, "central")) {
 834                central_irq_trans_init(dp);
 835                return;
 836        }
 837        if (!strcmp(dp->name, "virtual-devices") ||
 838            !strcmp(dp->name, "niu")) {
 839                sun4v_vdev_irq_trans_init(dp);
 840                return;
 841        }
 842}
 843
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.