10b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt#include <linux/types.h>
20b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt#include <linux/kernel.h>
30b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt#include <linux/irq.h>
40b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt#include <linux/smp.h>
50b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt#include <linux/interrupt.h>
60b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt#include <linux/init.h>
70b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt#include <linux/cpu.h>
80b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt#include <linux/of.h>
90b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt#include <linux/spinlock.h>
100b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt#include <linux/msi.h>
110b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
120b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt#include <asm/prom.h>
130b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt#include <asm/smp.h>
140b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt#include <asm/machdep.h>
150b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt#include <asm/irq.h>
160b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt#include <asm/errno.h>
170b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt#include <asm/xics.h>
180b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt#include <asm/rtas.h>
190b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
200b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt/* RTAS service tokens */
210b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidtstatic int ibm_get_xive;
220b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidtstatic int ibm_set_xive;
230b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidtstatic int ibm_int_on;
240b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidtstatic int ibm_int_off;
250b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
260b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidtstatic int ics_rtas_map(struct ics *ics, unsigned int virq);
270b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidtstatic void ics_rtas_mask_unknown(struct ics *ics, unsigned long vec);
280b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidtstatic long ics_rtas_get_server(struct ics *ics, unsigned long vec);
295ca123760177ed16cbd9bab609bff69eb8fc45bdMichael Ellermanstatic int ics_rtas_host_match(struct ics *ics, struct device_node *node);
300b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
310b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt/* Only one global & state struct ics */
320b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidtstatic struct ics ics_rtas = {
330b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	.map		= ics_rtas_map,
340b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	.mask_unknown	= ics_rtas_mask_unknown,
350b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	.get_server	= ics_rtas_get_server,
365ca123760177ed16cbd9bab609bff69eb8fc45bdMichael Ellerman	.host_match	= ics_rtas_host_match,
370b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt};
380b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
390b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidtstatic void ics_rtas_unmask_irq(struct irq_data *d)
400b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt{
41476eb4912601a8c01e6702b9a029f476b4b131d2Grant Likely	unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
420b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	int call_status;
430b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	int server;
440b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
450b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	pr_devel("xics: unmask virq %d [hw 0x%x]\n", d->irq, hw_irq);
460b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
470b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS)
480b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt		return;
490b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
500b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	server = xics_get_irq_server(d->irq, d->affinity, 0);
510b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
520b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	call_status = rtas_call(ibm_set_xive, 3, 1, NULL, hw_irq, server,
530b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt				DEFAULT_PRIORITY);
540b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	if (call_status != 0) {
550b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt		printk(KERN_ERR
560b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt			"%s: ibm_set_xive irq %u server %x returned %d\n",
570b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt			__func__, hw_irq, server, call_status);
580b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt		return;
590b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	}
600b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
610b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	/* Now unmask the interrupt (often a no-op) */
620b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	call_status = rtas_call(ibm_int_on, 1, 1, NULL, hw_irq);
630b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	if (call_status != 0) {
640b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt		printk(KERN_ERR "%s: ibm_int_on irq=%u returned %d\n",
650b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt			__func__, hw_irq, call_status);
660b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt		return;
670b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	}
680b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt}
690b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
700b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidtstatic unsigned int ics_rtas_startup(struct irq_data *d)
710b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt{
720b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt#ifdef CONFIG_PCI_MSI
730b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	/*
740b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	 * The generic MSI code returns with the interrupt disabled on the
750b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	 * card, using the MSI mask bits. Firmware doesn't appear to unmask
760b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	 * at that level, so we do it here by hand.
770b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	 */
780b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	if (d->msi_desc)
790b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt		unmask_msi_irq(d);
800b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt#endif
810b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	/* unmask it */
820b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	ics_rtas_unmask_irq(d);
830b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	return 0;
840b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt}
850b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
860b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidtstatic void ics_rtas_mask_real_irq(unsigned int hw_irq)
870b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt{
880b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	int call_status;
890b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
900b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	if (hw_irq == XICS_IPI)
910b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt		return;
920b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
930b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	call_status = rtas_call(ibm_int_off, 1, 1, NULL, hw_irq);
940b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	if (call_status != 0) {
950b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt		printk(KERN_ERR "%s: ibm_int_off irq=%u returned %d\n",
960b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt			__func__, hw_irq, call_status);
970b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt		return;
980b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	}
990b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
1000b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	/* Have to set XIVE to 0xff to be able to remove a slot */
1010b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	call_status = rtas_call(ibm_set_xive, 3, 1, NULL, hw_irq,
1020b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt				xics_default_server, 0xff);
1030b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	if (call_status != 0) {
1040b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt		printk(KERN_ERR "%s: ibm_set_xive(0xff) irq=%u returned %d\n",
1050b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt			__func__, hw_irq, call_status);
1060b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt		return;
1070b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	}
1080b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt}
1090b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
1100b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidtstatic void ics_rtas_mask_irq(struct irq_data *d)
1110b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt{
112476eb4912601a8c01e6702b9a029f476b4b131d2Grant Likely	unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
1130b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
1140b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	pr_devel("xics: mask virq %d [hw 0x%x]\n", d->irq, hw_irq);
1150b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
1160b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS)
1170b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt		return;
1180b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	ics_rtas_mask_real_irq(hw_irq);
1190b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt}
1200b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
1210b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidtstatic int ics_rtas_set_affinity(struct irq_data *d,
1220b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt				 const struct cpumask *cpumask,
1230b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt				 bool force)
1240b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt{
125476eb4912601a8c01e6702b9a029f476b4b131d2Grant Likely	unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
1260b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	int status;
1270b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	int xics_status[2];
1280b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	int irq_server;
1290b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
1300b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS)
1310b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt		return -1;
1320b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
1330b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	status = rtas_call(ibm_get_xive, 1, 3, xics_status, hw_irq);
1340b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
1350b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	if (status) {
1360b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt		printk(KERN_ERR "%s: ibm,get-xive irq=%u returns %d\n",
1370b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt			__func__, hw_irq, status);
1380b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt		return -1;
1390b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	}
1400b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
1410b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	irq_server = xics_get_irq_server(d->irq, cpumask, 1);
1420b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	if (irq_server == -1) {
1430b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt		char cpulist[128];
1440b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt		cpumask_scnprintf(cpulist, sizeof(cpulist), cpumask);
1450b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt		printk(KERN_WARNING
1460b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt			"%s: No online cpus in the mask %s for irq %d\n",
1470b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt			__func__, cpulist, d->irq);
1480b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt		return -1;
1490b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	}
1500b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
1510b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	status = rtas_call(ibm_set_xive, 3, 1, NULL,
1520b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt			   hw_irq, irq_server, xics_status[1]);
1530b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
1540b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	if (status) {
1550b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt		printk(KERN_ERR "%s: ibm,set-xive irq=%u returns %d\n",
1560b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt			__func__, hw_irq, status);
1570b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt		return -1;
1580b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	}
1590b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
1600b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	return IRQ_SET_MASK_OK;
1610b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt}
1620b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
1630b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidtstatic struct irq_chip ics_rtas_irq_chip = {
1640b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	.name = "XICS",
1650b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	.irq_startup = ics_rtas_startup,
1660b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	.irq_mask = ics_rtas_mask_irq,
1670b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	.irq_unmask = ics_rtas_unmask_irq,
1680b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	.irq_eoi = NULL, /* Patched at init time */
1690b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	.irq_set_affinity = ics_rtas_set_affinity
1700b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt};
1710b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
1720b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidtstatic int ics_rtas_map(struct ics *ics, unsigned int virq)
1730b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt{
174476eb4912601a8c01e6702b9a029f476b4b131d2Grant Likely	unsigned int hw_irq = (unsigned int)virq_to_hw(virq);
1750b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	int status[2];
1760b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	int rc;
1770b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
1780b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	if (WARN_ON(hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS))
1790b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt		return -EINVAL;
1800b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
1810b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	/* Check if RTAS knows about this interrupt */
1820b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	rc = rtas_call(ibm_get_xive, 1, 3, status, hw_irq);
1830b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	if (rc)
1840b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt		return -ENXIO;
1850b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
1860b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	irq_set_chip_and_handler(virq, &ics_rtas_irq_chip, handle_fasteoi_irq);
1870b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	irq_set_chip_data(virq, &ics_rtas);
1880b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
1890b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	return 0;
1900b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt}
1910b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
1920b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidtstatic void ics_rtas_mask_unknown(struct ics *ics, unsigned long vec)
1930b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt{
1940b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	ics_rtas_mask_real_irq(vec);
1950b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt}
1960b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
1970b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidtstatic long ics_rtas_get_server(struct ics *ics, unsigned long vec)
1980b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt{
1990b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	int rc, status[2];
2000b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
2010b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	rc = rtas_call(ibm_get_xive, 1, 3, status, vec);
2020b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	if (rc)
2030b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt		return -1;
2040b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	return status[0];
2050b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt}
2060b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
2075ca123760177ed16cbd9bab609bff69eb8fc45bdMichael Ellermanstatic int ics_rtas_host_match(struct ics *ics, struct device_node *node)
2085ca123760177ed16cbd9bab609bff69eb8fc45bdMichael Ellerman{
2095ca123760177ed16cbd9bab609bff69eb8fc45bdMichael Ellerman	/* IBM machines have interrupt parents of various funky types for things
2105ca123760177ed16cbd9bab609bff69eb8fc45bdMichael Ellerman	 * like vdevices, events, etc... The trick we use here is to match
2115ca123760177ed16cbd9bab609bff69eb8fc45bdMichael Ellerman	 * everything here except the legacy 8259 which is compatible "chrp,iic"
2125ca123760177ed16cbd9bab609bff69eb8fc45bdMichael Ellerman	 */
2135ca123760177ed16cbd9bab609bff69eb8fc45bdMichael Ellerman	return !of_device_is_compatible(node, "chrp,iic");
2145ca123760177ed16cbd9bab609bff69eb8fc45bdMichael Ellerman}
2155ca123760177ed16cbd9bab609bff69eb8fc45bdMichael Ellerman
216174ea471c395d70ee0c839ad59ca49f3b702de58Daniel Borkmann__init int ics_rtas_init(void)
2170b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt{
2180b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	ibm_get_xive = rtas_token("ibm,get-xive");
2190b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	ibm_set_xive = rtas_token("ibm,set-xive");
2200b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	ibm_int_on  = rtas_token("ibm,int-on");
2210b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	ibm_int_off = rtas_token("ibm,int-off");
2220b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
2230b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	/* We enable the RTAS "ICS" if RTAS is present with the
2240b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	 * appropriate tokens
2250b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	 */
2260b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	if (ibm_get_xive == RTAS_UNKNOWN_SERVICE ||
2270b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	    ibm_set_xive == RTAS_UNKNOWN_SERVICE)
2280b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt		return -ENODEV;
2290b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
2300b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	/* We need to patch our irq chip's EOI to point to the
2310b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	 * right ICP
2320b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	 */
2330b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	ics_rtas_irq_chip.irq_eoi = icp_ops->eoi;
2340b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
2350b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	/* Register ourselves */
2360b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	xics_register_ics(&ics_rtas);
2370b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
2380b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt	return 0;
2390b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt}
2400b05ac6e24807f0c26f763b3a546c0bcbf84125fBenjamin Herrenschmidt
241