~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/sparc/kernel/prom_irqtrans.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php