cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

prom_irqtrans.c (21954B)


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